yashsingh1/xdaforums huggingface dataset:
[Windows Mobile Software Development] 6Fg8:
Here's a union in vb.net - at least kind of :) good enough to marshal. Something similar should be available in C# too:

<StructLayout(LayoutKind.Explicit)> Structure FM_NOTIFICATION

Dim nCode As Integer

Dim dwTimeStamp As Integer

<FieldOffset(8)> Dim dwFrequency As Integer

<FieldOffset(12)> Dim eReason As Integer

<FieldOffset(8)> Dim nRDSCount As Integer

<FieldOffset(12)> Dim LPFM_RDS_GROUP As IntPtr

End Structure
[Windows Mobile Software Development] NetRipper:
Seems like a decent middle-way indeed. I suppose leaving the structs out of the union should work.

I'm just sad .NET doesn't resolve the struct properly. :) After some more googling it seems I was running into an issue with the .NET compiler, where it allows the user to compile something that the runtime doesn't support. These issues gave me a TypeLoadException during Runtime.

Can't wait to get home and get hacking again ;)
[Windows Mobile Software Development] flywhc:
I fixed that typo. Please update the function call to use correct name :P

Also return value of FMGetNotification is corrected - it should never return an error.

And it supports FMBAND_WIDEJPN (76.0 - 108.0 World wide) so you don't have to switch between bands now.
[Windows Mobile Software Development] NetRipper:
Thanks for the update :)

I'm still having a tough time with decoding the RDS. I've noticed your APITest (bundled with GFMAPI) doesn't decode the RDS but only displays the count. And the FMRadio test application uses events instead of notifications.

I'm getting garbled text with non-ascii characters. Also the radio text version is sometimes A and sometimes B, while on the same channel (PI doesn't change). Shouldn't one station always broadcast in the same version? Or at least not change within a sequence of groups?

I noticed that notifications use a struct size of 16 for a single group (4 bytes size, 4 * 2 bytes chunks, 4 bytes flags). The event system seems to use 12 bytes for each group, leaving out the 'flags'. The 'flags' are also garbled for me. Most of the time they are not one (or a combination of) FMRDS_CHUNK*_ERROR. I get values like 33686018.

I'm wondering if there's a problem with the marshalling to C#, if there's an issue with my parsing or the data returned by FMGetNotifications.

If anyone has some ideas, I'd love to hear them.

I think my next check will be to change the APItest example code a little to do a little parsing and see if I get the same results in C as in C#.
[Windows Mobile Software Development] 6Fg8:
Thanks flywhc for the updates, the continuos tuning is a very welcome addition :)

@NetRipper: sorry wanted to post some code for you but then forgot about it being busy with my own radio ;).

The function is called from the OnFMRDSGroupReceived callback:

TCHAR psname[30] = {0};
TCHAR g_RdsTxtMsg[100] = {0};
int RdsDIseg = 0;

...
void CALLBACK OnFMRDSGroupReceived(HFMRADIO hFMDevice, DWORD dwTimestamp, LPFM_RDS_GROUP lpRDSGroup, UINT nRDSCount)

....
for (uint i=0; i < nRDSCount; i++) {
DecodeRDS(lpRDSGroup[i].wChunk1, lpRDSGroup[i].wChunk2, lpRDSGroup[i].wChunk3, lpRDSGroup[i].wChunk4);
}
}
...

int DecodeRDS(int b1, int b2, int b3, int b4) {
int RdsGroupType = ((b2 & 0xf800) >> 11);
switch (RdsGroupType)
{
case 0:
{
RdsDIseg = (b2 & 3);

psname[RdsDIseg*2] = ((b4 & 0xff00) >> 8);
psname[RdsDIseg*2+1] = (b4 & 0xff);
psname[RdsDIseg*2+2] = 0;
break;
}
case 4: // 2A - Radio Text
{
int RdsDIseg = (b2 & 0xF);

g_RdsTxtMsg[RdsDIseg*4] = ((b3 & 0xff00) >> 8);
g_RdsTxtMsg[RdsDIseg*4+1] = (b3 & 0xff);
g_RdsTxtMsg[RdsDIseg*4+2] = ((b4 & 0xff00) >> 8);
g_RdsTxtMsg[RdsDIseg*4+3] = (b4 & 0xff);
g_RdsTxtMsg[RdsDIseg*4+4] = 0;

break;
}
default:
}
return 0;
}
[Windows Mobile Software Development] NetRipper:
Thanks for the example! Will be really useful if I'm going to test in C, and to see if I made any mistakes.

I'm glad you also use the FMGetNotification, which narrows the problem down to C# marshalling or my code. I'm currently decoding it almost the same as in your example, just a .NET variant. However, I've only been looking at group type 2A/2B. I had overlooked that 0A/0B also contains program name. I'm going to try and see if I can get data from that tonight.

Luckily the .pdf (posted somewhere in this thread) on the RDS specs is pretty clear. I just skipped ahead to "RadioText" too fast. ;)
[Windows Mobile Software Development] flywhc:
version is only changed when radio station broadcasts a new string.

dwFlags should be checked for error. 33686018 = 0x2020202. It should be 0 at most time. maybe there is a defect?
[Windows Mobile Software Development] NetRipper:
The errors were defined as:

chunk1_error 0x0001

chunk2_error 0x0010

chunk3_error 0x0100

chunk4_error 0x1000

The dwFlags doesn't match any of them. I'll look into the type 0A/0B first. If that works, then at least the chunks should be good. For now I don't check the flags and assume every chunk is OK. I'm getting a pretty solid radio signal as well and receiving 16 groups at a time (which seems to be the max I'm getting at any station).
[Windows Mobile Software Development] 6Fg8:
Here's another sample; using FMGetNotification in vb.net. Maybe it helps you find the marshaling problem. The code worked fine, meanwhile i've ported it to C++ for speed reasons, thanks to flywhc for the apitest sample ;)

<StructLayout(LayoutKind.Explicit)> Structure FM_NOTIFICATION
Dim nCode As Integer
Dim dwTimeStamp As Integer
<FieldOffset(8)> Dim dwFrequency As Integer
<FieldOffset(12)> Dim eReason As Integer
<FieldOffset(8)> Dim nRDSCount As Integer
<FieldOffset(12)> Dim LPFM_RDS_GROUP As IntPtr
End Structure

Public Declare Function FMGetNotification Lib "GFMAPI.dll" (ByVal hFMDevice As Integer, ByRef LPFM_NOTIFICATION As IntPtr) As Integer

Dim FMNOT As New FM_NOTIFICATION
Dim FMNOTp As IntPtr

FMNOTp = Marshal.AllocHGlobal(Marshal.SizeOf(FMNOT))

ret = FMGetNotification(hFM, FMNOTp)
FMNOT = Marshal.PtrToStructure(FMNOTp, GetType(FM_NOTIFICATION))
Select Case FMNOT.nCode
Case 0 'freq. change
...
Case 1 'RDS data
...
End Select
[Windows Mobile Software Development] NetRipper:
Thanks for the code example. I'm currently not using Explicit layout as I kept getting TypeLoadExceptions when using it in combination with a struct. Your solution should work fine indeed.

Anyway, I got it working now. The main thing I did wrong was swapping LOWORD and HIWORD. This was done in the FMRadio C++ wrapper, on which I originally based my code. However, it is not neccesary to do when receiving the data via the notification structure. The order is already correct then.

I removed the swapping before, as a test, but I figured it didn't work as I kept getting a lot of 'type 0' messages. However, I didn't know at that point yet that it contained the program name. ;)

So.. I now have programname working, and radiotext A and B. Thanks a lot for your help so far.

Still a question left for me is how do I detect when I fully received a message? I.e. when is it ready to display to the user? I don't want to display incomplete messages.

The documentation says this about group type 2:

However, I find this not to be working smoothly. It seems I sometimes receive a little piece of text A, and a bit of text B, and then I receive a bit more of text A. For now I'm just keeping two separate buffers, one for A and one for B. Furthermore I cannot find a similar principle for the program name of group type 0.

How do you guys do this?
[Windows Mobile Software Development] 6Fg8:
That kept me really busy for quite a while :)

Message formatting seems to be totally different depending on the broadcaster. Many of the private stations dont even send A/B messages, they simply transmit one A message after the other, and sometimes stop in the middle of a message and start with a new one. Our government broadcaster uses A/B messages but i also experienced abrupt stops and start with a different text. So avoiding incomplete messages on the screen seems impossible.

In another RDS doc i read that one should at least read the same message 3 times before displaying it, thats what my car radio actually does. Guess what, one of the (private) broadcasters sends messages only one time :mad:

What i currently do is check the RdsDIseg==0 and then send the previously buffered msg to the display. Buffering starts on the first RdsDIseg==0 after freq. change. Besides that i simply ignore the A/B as its obviously of no use - at least in my reception area.
[Windows Mobile Software Development] flywhc:
NetRipper, it is a defect - error flags returns 0x02020202 instead of 0x1111 if all chunks have error.

I fixed it in attached GFMAPI. This flag is important for accurate data such as TMC applications.

The whole package should be abandoned if chunk 1 has error because message type is unknowable.

My way to detect whether received all text for 2A:

- allocate a flags buffer for 64 elements, such as BYTE[64]

- set them to 0

- when received a character without error bit, set according flag buffer to 1

- when received a character with error bit, set according flag buffer to 2

- do not replace the buffer if new character has error bit but flag buffer is set to 2

- a full text is received when all 64 elements are set to 1, or end with 0A (or 0D? check RDS spec for terminate character)
[Windows Mobile Software Development] 6Fg8:
Since i linked the new 1.4 / 1.5 versions i have issues with the FMRadioBand settings. FMBAND_CCIR previously let me scan up to 108 MHz, now stops at 91 MHZ which is the FMBAND_JAPAN range. FMBAND_WIDEJPN works fine though.
[Windows Mobile Software Development] flywhc:
Sorry. another bug. :P

Thanks for testing.
[Windows Mobile Software Development] 6Fg8:
No problem, thanks for taking care :)
[Windows Mobile Software Development] flywhc:
I have tested Band 0,1,2 by using APITest.exe a few times I cannot reproduce the issue.

Only Band 1 stop at 91 MHz, band 0 can seek up to 108.0

Can you try APITest with GFMAPI 1.5 please?
[Windows Mobile Software Development] 6Fg8:
APITest works fine. Now i found why it doesnt work in my app: i specify the band in the FMPowerOn call. If i subsequently call FMSetProp(...FMPROP_BAND) it works perfect :)
[Windows Mobile Software Development] flywhc:
I don't understand.

You can see in APITest source code:

case IDC_POWERON:

nRet = FMPowerOn(hFM, TRUE, FMBAND_CCIR);

It also sets band to CCIR when power on. I tested APITest without FMSetProp it can seek up to 108.00.
[Windows Mobile Software Development] 6Fg8:
Maybe it's related to my device, i noticed some strange behaviour during the last days which points to a hardware problem. Reception is really bad, i only get very strong stations. Looks like i have to send it in for repair.
[Windows Mobile Software Development] 6Fg8:
I finally figured out what went wrong with my FMBAND issues.

In my FM app i have a "scan band" function to initially save frequencies to presets buttons, and what it does is set the frequency to the start of the CCIR Band (87.5 MHz) and then seek forward. Unfortunately, this leads to the effect that the FMBAND somehow switches to Japan setting (76-91) and then of course scanning stops at 91 MHz because of band margin reached. Querying FMBAND still reports CCIR (returns 0 on FMGetProp).

The same occurs in APITest if you use setprop frequency to 87500 and then seek back, you'll find yourself at 76000 when band margin is reached.

That works the other way round too: set frequency to >91 MHz and scan up, FMBAND switches automatically to CCIR.

Dont know if thats intended or not, or has anything to do with FMAPI (i guess not). Once one knows, workaround that is pretty easy - set initial frequency to 108000, seek foreward and you're fine.
[Windows Mobile Software Development] yo9gly:
reception over 108 MHz ?

it is possible to have reception over 108 MHz ? (144-146MHz)

it is possible to change the demodulation mode? (AM . SSB ;)

Tnx.
[Windows Mobile Software Development] cr2:
hehe. it may be possible if you know what (and where) to patch the DSP firmware 8)
[Windows Mobile Software Development] 6Fg8:
even if we could tune the 2m amateur band, and even if we had a BFO and AM receiver for SSB reception, it wouldnt be of much use. ZF filters for FM broadcast receiption are ~150 kHz wide, compared to 12 KHz narrow FM or 2.7 kHz SSB used by HAMs.
[Windows Mobile Software Development] yo9gly:
the level of the demodulated signal will be small than normal , but inteligibile -the filter are biger than signal (will affect the selectivity , IMD, etc.) Narrow FM (+/-2.5KHz) is not used .Classic FM used in 2m are +/-5KHz.

73!

:)
[Windows Mobile Software Development] 6Fg8:
OK wont make much sense to go into a detailed discussion (at least not in this thread), but i think you got the point. So for the practical use, i did try to receive 2m band with FM broadcast filter settings (just out of curiosity, with an ICOM R20) and the answer if that would be possible on a mobile device, i think we'd both agree is no.

But, curious as i am, i will give ATC radiocomm a shot, if it leads to something i'll definitely write some code for a receiver.
[Windows Mobile Software Development] yo9gly:
You can test with two handy switching between WFM, FM or NFM

As handy, Kenwood th7E have all this mode.

Sometimes , to receive weak FM signals, is better to switch to NFM ! :)

In ham radio communication , the inteligibility is an option..... :)
[Windows Mobile Software Development] kzd76:
Callbacks

Hello!

Thanks for suggesting me some keywords how to google some examles to call c dll functions from c#. Power On/Off, seeking and volume changing is working perfectly, but I cannot access features like RDS data and FM notifications. Somebody asked this before and you mentioned the wndproc(), but this is not working under Visual Studio .Net c# Compact Framework as Message is not implemented to System.Windows.Forms :-(, and the existing Microsoft.WindowsCE.Forms.Message is not fit to wndproc().

So I did some google search and found delegates. So I have the followings now:

delegate void FMNotificationDelegate(FM_NOTIFICATION FMNotification);

[DllImport("GFMAPI.dll")]
static extern int FMGetNotification(int hFMDevice, FMNotificationDelegate FMNotification);

void OnFMNotification(FM_NOTIFICATION FMNotification)
{
LogWrite("FM notification!");
}

And later, when everything was ok with powering on the radio, setting volume and audiopath and tuned to the first station with seeking:

nRet = FMGetNotification(hFM, OnFMNotification);
LogWrite("Result for get notification: " + GetErrorStr(nRet)); //hFM: handle for the opened FM radio

So as I can understand it, I have delegate and if something is triggering it, it will create a log entry with my LogWrite function, and with FMGetNotification I set this delegate event to be called.

On paper it is working fine, but the OnFMNotification event is never happening, however i have success for the FMGetNotification.

If somebody help me, it would be very appreciated.

Thanks,

KZD
[Windows Mobile Software Development] NetRipper:
KZD,

I've got my C# wrapper working at the moment. It wraps all GFMAPI calls to C# equivalents. If you wait a few hours (when I'm home from work) I can post this .dll so you can use the API from .NET. It has notifications working as well.

I'm now working on a simplified FMRadio wrapper for this wrapper. Something that makes it easier to use the API, and also includes stuff like the wndproc thing, decoding RDS programname and text. Also making use of the .NET 'events'. However that'll take a bit longer before I finish it.

@flywhc

Do you think I can post my .net binaries and/or source in this thread or do you want me to make a seperate thread?

[edit]

@KZD,

In case you decide to continue on your own, in .NET compact framework there's the MessageWindow which you need to extend from. Look here for an example out of my code.

You have to pass the messageWindow.Hwnd to the FMRegisterNotification function. After that, when you receive the notification in your extended MessageWindow, you call FMGetNotification.
[Windows Mobile Software Development] kzd76:
Thanks! I can wait, of course.
[Windows Mobile Software Development] flywhc:
The latest version of GFMAPI provides both windows message and event, but not callback function.

You can use subclass to handle windows message:

http://msdn.microsoft.com/en-us/magazine/cc188736.aspx

Or use waitforsingleobject wait for that event object.

FMGetNotification uses a structure as the second parameter. Look at 6Fg8's post before for this structure in c#.

6Fg8, It seems a "feature" of htc FMS driver...

Update: 87500 issue is a bug of GFMAPI. I will fix this soon
[Windows Mobile Software Development] NetRipper:
Here's that wrapper so far. It's not really documented, but it's exactly like the GFMAPI. I even kept structnames etc mostly the same.

http://www.netripper.nl/raphael/gfmapi.net/GFMAPI.NET_v0.1.zip

To get you started on the notifications stuff, here's a minimal snippet. I figure this is enough to get you working. Other stuff is omitted.

http://netripper.pastebin.com/f7fcae346

Oh yea, only the FMGetDevInfo is not in there yet. I can't get this function to work yet. Always getting an InvalidParameter. And whatever I do (by ref, or out param) I never get any data. If anyone got this working, could you share the struct and method call definitions?
[Windows Mobile Software Development] 6Fg8:
A bit tricky though, but working. And yes, vb.net again :) Sorry, i'm more the vb gal, kinda first language ...

Public Declare Function FMGetDevInfo Lib "GFMAPI.dll" (ByVal nDeviceID As Integer, ByVal lpFMDevInfo As IntPtr) As Integer

Structure FMDEVINFO
Dim dwSize As Integer
Dim dwAPIVersion As Integer
Dim dwFMVersion As Integer
Dim dwCapabilities As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=20)> Dim szDeviceName As String
End Structure

Dim fmdi As New FMDEVINFO
fmdi.dwSize = Marshal.SizeOf(fmdi)
Dim fmdip As IntPtr = Marshal.AllocHGlobal(fmdi.dwSize)
Marshal.StructureToPtr(fmdi, fmdip, False)

hFM = FMOpen(0)
ret = FMGetDevInfo(0, fmdip)
fmdi = Marshal.PtrToStructure(fmdip, GetType(FMDEVINFO))
[Windows Mobile Software Development] flywhc:
You are welcome to post here if you like to.

I was thinking to write such wrapper since so many questions about C# interface.

I will add link to your file/post on the first post of this thread.
[Windows Mobile Software Development] 6Fg8:
Thanks for looking into that. I dont think its important enough to justify additional checks in GFMAPI.

I'm almost done with my FMplayer, will soon release a first beta for testing.

What would be an interesting info is the "real" stereo reception of the tuner, the one that is detected from the pilot signal. Dont know if that is requestable from FMS driver, but maybe you stumbled over it ;)
[Windows Mobile Software Development] NetRipper:
Nice. The ByValTStr and the SizeConst were the key. Fortunately I've got it working without manually allocating memory as well. Here's the pastebin in case you're curious: http://netripper.pastebin.com/f7883e0db

Thanks! Appreciated very much.

As the FMGetDevInfo is working now, here's a newer version:

http://www.netripper.nl/raphael/gfmapi.net/GFMAPI.NET_v0.2.zip
[Windows Mobile Software Development] 6Fg8:
curious is my second name :D Thanks for the pastebin.

Great that VB and C# are so similar.
[Windows Mobile Software Development] 6Fg8:
The first version of Power Radio is released:

http://xdaforums.com/showthread.php?p=4046501#post4046501
[Windows Mobile Software Development] flywhc:
I fixed that 87.5MHz bug in my code. Hopefully there is no more bugs :P

FMS api does support a callback function that indicate stereo state.

but this function has never been called. :(

This callback function is also implemented in HTC FM radio application but I can't see any indication of stereo signal on FM Radio.

Usage of original FMS driver is on the first page, if you are interested.

I thought frequency is 100KHz increment but I can set a frequency to 87550.

Then it cannot tune to any channel if I press seek buttons because frequency is always end with 50KHz
[Windows Mobile Software Development] JohnLaShot:
Hello flywhc,

please do not forget the millions of Artemis users.:)

I would be great, if you could manage to resolve the driver problems regarding Artemis.

Thank you so much.

John
[Windows Mobile Software Development] flywhc:
As I posted before in this thread and Artemis forum, I need a VC++ developer with Artemis to help me. I am stuck because I don't have Artemis.
[Windows Mobile Software Development] 6Fg8:
Could you please elaborate on that?

I tried my luck with FMGetProp CARRIERDETECT but to no avail, returns error 50 on my device.
[Windows Mobile Software Development] L_o_k_i:
@flywhc

Hi,

I'm using HyperGPS from Beemer, and PowerRadio from 6Fg8. On both of them, there are sometimes errors on the name of a station for example (and maybe with the other data too). After some readings about TMC/RDS, I've found out it's possible to detect and correct errors. My question is: do you detect/correct these errors or it must be done in HyperGPS and PowerRadio?

BTW, thanks for your great work!
[Windows Mobile Software Development] 6Fg8:
GFMAPI delivers RDS packets, not station names or RDS text messages. Each RDS packet comes with a status bit which shows if its well or possibly malformed.

Interpreting the RDS packets and checking status bits is up to the application developers which use GFMAPI. In case of PowerRadio, the status bits are currently ignored, which could lead to the symptoms you describe, specially in weak reception conditions. For PowerRadio its already on the todo list but will take some time.

In short words: it's not a problem within GFMAPI.
[Windows Mobile Software Development] L_o_k_i:
OK 6Fg8, thanks for your quick answer.

EDIT: I know GFMAPI delivers raw RDS packets. So each RDS block comes with one status bit, and this bit tells you if the entire block is OK or not? If so, then you don't know which bit in the block is malformed... And you cannot correct it... That's right?
[Windows Mobile Software Development] NetRipper:
That's correct. The GFMAPI does it this way. Each block is received and a flag indicates whether a block has an error.

I'm not sure how the FMSAPI.DLL works though (which is used by the GFMAPI). The raw rds protocol has 10-bit checksums for each 16-bit block, which should be used for error detection and _may_ be used for error correction. If the FMSAPI provides the 10-bit checksums, then flywhc may be able to implement some attempt to recovery. I think this was mentioned in the RDS documentation.
[Windows Mobile Software Development] 6Fg8:
Right, the only reasonable reaction to a packet marked bad is discard it.

I'm not 100% sure where errorhandling is actually done in our devices, but usually its done on the receiver chip, which then delivers a corrected datablock to the drivers or marked bad if errors couldnt be corrected. Sure flywhc can shed light on these details.
[Windows Mobile Software Development] flywhc:
Yes, error handling is done in the chip.

From some old discussion in this thread, you can see what I got from FMS driver:

checkword can be 0x20 0x21 0x22 0x24 or 0x28 0x29 0x2A 0x2C

Lower 3 bits indicates chuck number, the 4th bit indicate checksum error. high 4 bits are always 0010.

I don't have programming sheet for BRF6350 so I don't know what 0010 means.

you could ignore those data with error bit but side effect is user has to wait for longer time for a full RDS string. That is why HTC FM radio sometimes takes long time to display a station name but xFMRadio display station name in a few seconds. RDS has a very slow data transmission rate. And wrong data bit maybe in the checkword not in the data chunk so that data chunk with error flag may be useful.
[Windows Mobile Software Development] L_o_k_i:
Thank you flywhc for your answer, that's much clear now! :D
[Windows Mobile Software Development] mhemart:
@flywhc :

Sorry, I've been away from the forum for a long moment (too much working). I asked my friend if he was able to help me with VC++ but it seems too difficult for him too. So I'll try to find VC++ programmers interrested to collaborate to your project.