Wireless
Stephen Leary (372) 272 posts |
Ok. So I want to develop a module that implements the OS level wireless interaction for drivers. Basically anything that DCI doesnt do that wireless needs. Examples of this are: - Signal strength, Channel ID, SSID scanning, Security (later) I’d like to architect this in such a way that a network driver can call a bunch of SWI’s to (un)register with the wireless module and then all userland interaction can take place via that module. This is a longer term project and I hope to get people onboard doing small parts of the work. Discuss. |
Jeffrey Lee (213) 6048 posts |
I know nothing about implementing wireless drivers, and very little about DCI, so don’t expect me to be much help with designing the API. You’ll probably want to get in touch with WPB - I know he’s keen to get the IGEP wireless working. |
Stephen Leary (372) 272 posts |
So first thing. If I have an SWI where I want to return an enumeration/list. Is the best thing to do return a linked list for the caller? or is there a better mechanism for enumerations? |
Jeffrey Lee (213) 6048 posts |
I guess it depends on how often the contents of the list will change (particularly, addition and removal of elements). Typically RISC OS uses interfaces similar to OS_GBPB 9 when enumerating things. I.e. you repeatedly call the same SWI, and the SWI returns one (or more) items on each call, typically by copying the data into a user-supplied buffer. I think the advantages of such an API are two-fold:
|
Stephen Leary (372) 272 posts |
I agree with the principle of copying things to a caller’s local memory. But i dont like the idea of calling a SWI repeatedly to get subsequence items. At least not without some context to make the calls from different applications orthogonal. Linked lists are usually the safest way to go as on the fly changes are safe as removing/adding an item can be done atomicly. |
Colin (478) 2433 posts |
I’d copy items into callers memory using swis. As I see it, if you pass a pointer the client can: 1) edit/corrupt your list Is undesireable for the obvious reason. 2) use the list directly Is undesirable as you can’t know what the client is doing with the pointers when you delete/add/change the list. 3) copy the list Copying the list doesn’t keep it up to date for the client so it would need to keep polling the swi looking for changes. The copying has to be done before the list can change otherwise pointers may be invalid. Using a swi call to enumerate the list instead of returning a pointer (like to Wimp_RedrawWindow, Wimp_GetRectangle) removes problem 1 and 2 and can do the same as 3 with the same problems. If the act of calling any swi can result in a change in the internal list (making the swi method undesirable) then this is a problem for pointers as well, as clients may call swis while traversing a pointer list. If a changing list is a problem one alternative could be module service calls. After a client calls swi enumeratelist you broadcast a series of service calls one for each item in the list. The client can then create its own list – other clients may take this opportunity to recreate their lists if they want. When a list item appears/disappears/changes it is broadcast as a service call and clients can update their lists. ‘Change’ service calls would be independent of list enumeration service calls so while receiving enumeration service calls the client may get a ‘change’ service call which it can use to keep items it has already received up to date. The result is that the client’s copy is kept up to date and is informed when an item has changed. Against the scheme it may be too slow – I don’t know. You could implement a similar scheme with wimp messages. |
W P Blatchley (147) 247 posts |
Yep, I’m here. I’ve been in touch with Stephen already. Before xmas I was working on trying to set the IGEP’s hardware up ready for the wireless to be used. That involves uploading a couple of firmware files to the card. I’ve been off the project for a good month or more now, but I’ll be getting back to it now. If I can get that going, I’ll be looking to Stephen to direct me as to what needs doing next!
Allow me to muse way out of my depth here! Certainly the above is a mechanism that’s commonly used in RISC OS, but I’ve never understood how it can handle multiple calls from different contexts. I suspect it can’t! There’s precedent for other methods of returning lists of data, like OS_FindMemMapEntries, but the data it’s returning is nice and simple. If you were returning strings or other variable-length data, it could be messy. Many calls have to be called twice: once to determine the size of the data you’ll be getting back, and once to actually get the data. I suppose there’s a theoretical risk of a context switch between two such calls with that model too, though the consequences wouldn’t be so serious – just a buffer under/overflow. If you introduce the idea of a context handle, I would think that creates a lot more housekeeping work for the implementer of the SWI. But maybe that’s the safest way to go? In short, I don’t know! Just adding a few more ideas in here to be discussed by cleverer people! |
Colin (478) 2433 posts |
I think an OS_GBPB style swi is the way to go. The context is in the R4 number. The client only knows about 2 states of this number – 0 and -1. Any other value is used by OS_GBPB to work out the context. I’d probably go for something like WLan_ReadEntries On entry R0 = reason code. The reason code relates to the size of the entry returned so if more info is available in future and the entry becomes bigger a new reason code can be added which includes the new info. Because the reason code determines the size of one item you don’t need a call to determine the required buffer size. R1 = buffer pointer On exit R0-R2 is preserved. If you can’t return an entry immediately you can exit with R3=0 R4<>-1 so that the call becomes non blocking. The scheme also allows you to validate the magic number and return an error if it is invalid. So at it’s simplest level if there are more entries you return a pointer to the last item read in r4 and when WLan_ReadEntries is called again if the pointer in R4 has been deleted you return an error. As pointers can be reused, in your internal representation of the list I’d be inclined to give each list item a unique ID and return that in R4. The list can be searched for the ID to determine if it still exists or not. With the list being small the overhead caused by validation won’t be great. |
Stephen Leary (372) 272 posts |
Personally I hate this type of approach. Its very old and requires that the OS holds state about the caller. You really want to push this sort of work to the caller. I dont like the idea of an service holding state about a client in any kind of situation as it doesnt scale and means cleanup is required. |
Stephen Leary (372) 272 posts |
Sorry i’ve realised my stupidity. Yes that works. |
Stephen Leary (372) 272 posts |
So the next thing to discuss is the development platform. GCC or Norcroft? I’d love to use GCC more generally if the assembly directive worked half as nice as the Norcroft compiler. However Norcroft produces nicer assembly from what I can tell. |
Stephen Leary (372) 272 posts |
So i’m going with GCC. I have the beginnings of my module. I need a way to enumerate all the network cards the OS knows about and then find a way to ask them what SWI calls they support. Any pointers would be warmly welcomed. The first stage will be to get an iwconfig command listing the NICs as having no wireless extensions. Then move to try and define what the drivers will need to implement for the Wireless module to work. |
James Peacock (318) 129 posts |
As all NICs will need a DCI driver, it would seem that you are in effect extending the DCI interface. If so, I would suggest adding a single new flag to the set returned by <Base>_Inquire SWI indicating that the driver supports wireless, maybe leaving a bit of a gap to allow for any we don’t know about (say bit 20). Existing (non-wireless) drivers should return 0 for unused bits. Further wireless specific stuff can be defined in terms of new SWIs which wireless aware drivers would implement which should only be called if that flag is set. You can enumerate all network units using service call 0×9b: SYS "OS_ServiceCall",0,&9B TO item% WHILE item%<>0 next% = item%!0 dib% = item%!4 SYS "OS_Module",7,,item% PRINT "Name: ";FNstr(dib%!4);dib%!8 item%=next% ENDWHILE END DEF FNstr(ptr%) LOCAL e$ SYS"XOS_GenerateError",ptr% TO e$ =e$ You can see EtherUSB’s handler for this service call to see what is in dib%. DCI drivers make service calls to inform protocol modules (e.g. Internet) when new units are added or removed, which can be used to track the current list of available drivers. |
Stephen Leary (372) 272 posts |
Thanks James, This makes sense. Hoping to get the structure in place over the next few weeks so people can start bolting various bits to it. |
James Peacock (318) 129 posts |
If you are going to have lots of wireless SWIs, then perhaps having a single SWI with a reason code would be better. Also I’d advise having a flags argument for each call/SWI, even if it is always zero initially, to allow for modifying the API while maintaining backwards compatibility. |
Stephen Leary (372) 272 posts |
Good advice indeed! I’ll do as you suggest. It would be very useful to get a review from yourself and Jeffrey before I release the API for general consumption. |