J'écris une application dans Qt pour être déployée sur la plate-forme Symbian S60. Malheureusement, il doit avoir la fonctionnalité Bluetooth - rien de vraiment avancé, juste une simple découverte du socket client et de l'appareil RFCOMM. Pour être exact, l'application devrait fonctionner sur deux plates-formes - Windows PC et S60 précité. Bien sûr, comme Qt n'a pas de support Bluetooth, il doit être codé en API native - Winsock2 sous Windows et Symbian C++ sur S60 - je suis en train de coder une couche d'abstraction simple. Et j'ai quelques problèmes avec la partie découverte sur Symbian.Symbian C++ - découverte Bluetooth synchrone avec timeout à l'aide de RHostResolver
L'appel de découverte dans la couche d'abstraction doit fonctionner de manière synchrone. Il bloque jusqu'à la fin de la découverte et renvoie tous les périphériques sous la forme QList
. Je n'ai pas le code exact en ce moment, mais j'avais quelque chose comme ça:
RHostResolver resolver;
TInquirySockAddr addr;
// OMITTED: resolver and addr initialization
TRequestStatus err;
TNameEntry entry;
resolver.GetByAddress(addr, entry, err);
while (true) {
User::WaitForRequest(err);
if (err == KErrHostResNoMoreResults) {
break;
} else if (err != KErrNone) {
// OMITTED: error handling routine, not very important right now
}
// OMITTED: entry processing, adding to result QList
resolver.Next(entry, err);
}
resolver.Close();
Oui, je sais que User::WaitForRequest
est mal, que le codage comme Symbian, j'utiliser des objets actifs, etc. sur. Mais ce n'est pas ce dont j'ai besoin. J'ai besoin d'une manière simple et synchrone de faire la découverte de l'appareil.
Et le code ci-dessus ne travail. Il y a une bizarrerie, cependant - j'aimerais avoir un temps mort pendant la découverte. C'est-à-dire, je veux que la découverte ne prenne pas plus de, disons, 15 secondes - paramétrée dans un appel de fonction. J'ai essayé de faire quelque chose comme ceci:
RTimer timer;
TRequestStatus timerStatus;
timer.CreateLocal();
RHostResolver resolver;
TInquirySockAddr addr;
// OMITTED: resolver and addr initialization
TRequestStatus err;
TNameEntry entry;
timer.After(timerStatus, timeout*1000000);
resolver.GetByAddress(addr, entry, err);
while (true) {
User::WaitForRequest(err, timerStatus);
if (timerStatus != KRequestPending) { // timeout
resolver.Cancel();
User::WaitForRequest(err);
break;
}
if (err == KErrHostResNoMoreResults) {
timer.Cancel();
User::WaitForRequest(timerStatus);
break;
} else if (err != KErrNone) {
// OMITTED: error handling routine, not very important right now
}
// OMITTED: entry processing, adding to result QList
resolver.Next(entry, err);
}
timer.Close();
resolver.Close();
Et ce code Kinda œuvres. Plus encore, la façon dont cela fonctionne est fonctionnellement correct - le délai d'attente fonctionne, les périphériques découverts jusqu'à présent sont retournés, et si la découverte se termine plus tôt, alors il quitte sans attendre le minuteur. Le problème est - il laisse un fil perdu dans le programme. Cela signifie que lorsque je quitte mon application, son processus est toujours chargé en arrière-plan, ne rien faire. Et je ne suis pas le type de programmeur qui serait satisfait d'une "correction" comme faire le bouton "exit" tuer le processus au lieu de quitter gracieusement. Laisser un fil perdu semble une fuite de ressources trop sérieuse.
Y at-il un moyen de résoudre ce problème? Cela ne me dérange pas de tout réécrire à partir de zéro, même en utilisant des API totalement différentes (du moment que nous parlons d'API Symbian natives), je veux juste que ça fonctionne. J'ai lu un peu sur les objets actifs, mais cela ne semble pas être ce dont j'ai besoin, car j'ai juste besoin que ça fonctionne de manière synchrone ... Dans le cas de changements plus importants, j'apprécierais des explications plus détaillées, puisque je suis nouveau sur Symbian C++, et je n'ai pas vraiment besoin de le maîtriser - ce petit module Bluetooth est probablement tout ce dont j'ai besoin pour y écrire dans un avenir prévisible.
Merci d'avance pour toute aide! :)
Bien sûr, il n'y a pas d'utilisateur :: WaitForRequest qui accepte les trois années TRequestStatus. Cependant, dans ce cas, vous pouvez utiliser User :: WaitForAnyRequest() car vous savez que seuls les trois TRequestStatus que vous avez seront utilisés pour signaler le thread. Pas tout à fait aussi joli mais devrait fonctionner. Il peut être préférable de le refaire à l'aide d'objets actifs, mais cela rend l'initialisation de exitStatus plus difficile (puisqu'il appartiendra à l'un de vos objets actifs, il devra donc être transmis du sous-thread au thread principal). – MathewI
Merci pour votre aide ... Je pensais à créer un thread séparé pour effectuer la découverte, et en utilisant des objets actifs au lieu de 'User :: WaitForRequest' là ... Le thread principal l'attendrait alors. Que pensez-vous de ce genre d'approche? – kFYatek
Oh, et en passant - pour autant que je comprends la documentation de l'API, il _is_ un 'WaitForRequest' pour trois ou plusieurs objets' TRequestStatus' - Je parle de 'WaitForNRequest' - il faut un tableau de pointeurs vers' TRequestStatus 'et la taille de ce tableau. Cependant, je ne comprends pas vraiment votre approche - suis-je censé créer un nouveau 'RThread' juste pour l'annuler plus tard? Quel est le point dans tout ça? Je suppose qu'il y a un thread implicitement créé par l'API, auquel je n'ai pas d'accès explicite ... – kFYatek