Symbian OS C++ for Mobile Phones VOL 1 PHẦN 9 potx

73 284 0
Symbian OS C++ for Mobile Phones VOL 1 PHẦN 9 potx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

The data formats are as follows:  GDP PDU. This is the chunk of data that's passed down to our GDP implementation through the CGdpSession interface, along with protocol-specific addressing information.  GDP-SMS PDU. Here, we have put a unique pattern on the front so that we can spot our messages at the far end. In this case, "//BATTLESHIP". Note, alternatively, SMS Port numbers can be used. The destination address passed down through the GDP interface is encoded directly into the SMS PDU, along with the SCA if present. 20.2.3 The GDP-SMS Implementation The structure of the SMS code is illustrated below. The main component from the client's point of view is the CGdpSmsComms class shown in the center of the diagram. This implements CGdpSession, through which all client operations are performed (save for initially creating the object). This center class actually provides a simple, thin interface, or facade,into the various components used for SMS communications. The three main subcomponents, CGdpSmsSender, CGdpSmsReceiver, and CGdpSmsResourceManager actually carry out the three tasks required for the GDP session (Figure 20.5). Figure 20.5 Note It is interesting to note that the session class, CGdpSmsComms, has no state itself. This is because GDP-SMS, along with all GDP implementations, is actually stateless. This may come as a surprise after all the talk about state machines, but it does make sense when you consider that GDP is a connectionless, best-efforts datagram protocol. All the state is concerned with is attempting to get a specific packet in or out of the machine – no significant state is held over between packet transmissions. Through the following sections, you'll see an in depth example of how to use the Symbian OS sockets API to communicate over SMS. The CGdpSmsSender class handles the task of creating an SMS message and sending it over via the socket server. It comes to life whenever the client code calls the SendL() member of the GDP-SMS session object, and continues asynchronous activity until the packet is successfully sent or has completed a bound number of unsuccessful retries. Sender As Figure 20.6 shows, it is a very simple process to send GDP packets via SMS: Figure 20.6  Send : Open a socket, stream the SMS message to the socket, and call an RSocket::Ioctl() to start the send in action. It is possible that the send operation may fail. I deal with this by using the handler mechanism of the generic state machine to do a limited number of retries before giving up. The Ioctl() call on the socket is asynchronous in nature, so the CGdpSmsSender task class is derived from CGdpSmsStateMachine as follows (from gdpsms.h): class CGdpSmsSender : public CGdpSmsStateMachine // { public: class TSenderState : public CGdpSmsStateMachine::TState { public: TSenderState(CGdpSmsSender& aSmsSender); protected: CGdpSmsSender& iSender; }; class TSendMsgState : public TSenderState { public: TSendMsgState(CGdpSmsSender& aSmsSender); void EnterL(); TState* CompleteL(); TState* ErrorL(TInt aCode); void Cancel(); private: }; friend class TSendMsgState; public: CGdpSmsSender(CGdpSmsResourceManager& aResMan); ~CGdpSmsSender(); void OpenL(MGdpPacketHandler& aHandler); void Close(); void SendL(const TDesC8& aAddress, const TDesC8& aData); protected: void Reset(); TState* ErrorOnStateEntry(TInt aError); TState* ErrorOnStateExit(TInt aError); private: RSocket iSocket; CSmsMessage* iSmsMsg; TPckgBuf<TUint> iOctlResult; TBool iGotScAddress; MGdpPacketHandler* iHandler; TInt iRetries; // Remaining // States TSendMsgState iSendMsgState; }; As you can see, this class actually inherits from CGdpSmsStateMachine, which is a very slightly specialized version of the abstract CGdpStateMachine class. I will introduce the facilities it adds when we discuss the resource manager later on. The sender state machine defines a concrete state class – TSendMsgState along with one instance variable. This is the state object that the current state pointer in the abstract state machine will point to. The state class has a reference back to the sender object that it belongs to – this information is not automatically provided by the nesting construct, because it only affects the class relationship, not any specific object (or instance) relationship. I provide this reference variable in a generalized TSenderState class that all the concrete states derive from. We'll now trace through the operation of sending a GDP-SMS message. The OpenL() function is called when the client code calls the corresponding function in CGdpSmsComms. This puts it into an initial state, by calling Reset(), ready to accept requests to send packets. It also stores a pointer to the GDP packet handler. This will be used to inform the handler of a completed send operation. The state machine gets kicked into life every time the CGdpSmsComms::SendL() is called; this is the only point of contact with the GDP client in the whole process of sending. void CGdpSmsComms::SendL(const TDesC8& aAddress, const TDesC8& aData) { RDebug::Print(_L("CGdpSmsComms::SendL() Called.")); __ASSERT_ALWAYS(iSender != NULL, GdpUtil::Fault (GdpUtil::EProtocolNotOpen)); iSender->SendL(aAddress, aData); } This invokes the SendL() function within the sender class, which looks like this: void CGdpSmsSender::SendL(const TDesC8& aAddress, const TDesC8& aData) { if (IsActive()) return; // Don't leave just quietly drop the overflow packet // Create the SMS message CSmsBuffer* smsBuffer = CSmsBuffer::NewL(); iSmsMsg = CSmsMessage::NewL(iResMan.iFs, CSmsPDU::ESmsSubmit, smsBuffer); TSmsUserDataSettings smsSettings; smsSettings.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet7Bit); smsSettings.SetTextCompressed(EFalse); // Convert address to unicode string required by CSmsMessage __ASSERT_ALWAYS(aAddress.Length() <= KGdpMaxAddressLen, GdpUtil::Fault(GdpUtil::EBadSendAddress)); TBuf<KGdpMaxAddressLen> bufAddress; bufAddress.Copy(aAddress); iSmsMsg->SetUserDataSettingsL(smsSettings); iSmsMsg->SetToFromAddressL(bufAddress); iSmsMsg- >SmsPDU().SetServiceCenterAddressL(KServiceCenterNumber); // Convert data into unicode as CSmsBuffer will convert to appropriate // format for us. TBuf<KGdpSmsSduMaxSize> buf; buf.Copy(aData); // Insert our SMS pattern header so that our receiver is able to detect // the incoming message, and then append the data. smsBuffer->InsertL(0, KGdpSmsHeaderTag); smsBuffer->InsertL(KGdpSmsPatternLen, buf); iRetries = KGdpSmsSendRetries; Reset(); ReEnterCurrentState(); // Kick us off again. } If we're already busy sending an SMS message, we simply give up on this new request and return – it is up to the client to ensure we're not given more packets than we can cope with. We create a CSmsBuffer object to contain the text contents of our message. CSmsBuffer maintains the text content of the message in an array of TText objects, and provides functions to modify the content. We then create a CSmsMessage object. This object helps to hide the underlying complexity of ensuring that the message is structured in the correct network format of an SMS message. TSmsUserDataSettings allows us to specify that the message is stored in 7-bit format. SMS supports both 7-bit and 8-bit data transport, but only 7-bit is universally implemented, so that's what I've chosen to use here. SMS supports a maximum message length of 160 7-bit characters. aAddress contains the telephone number of the receiver. The only test we do with this number is to see that it does not exceed a certain size. Interestingly, CSmsMessage accepts a Unicode string for the address to which the SMS will be sent, so we must convert the address from narrow text. We can do this by copying it into a Unicode descriptor. We then set the service center number. Before inserting aData into the CSmsBuffer object, we have to ensure that we first insert the pattern that will enable the receiver to recognize the message as a GDP SMS message. We then set up how many times we're going to retry sending if the first attempt fails and then set the state machine going. The first time a packet is sent, the current state (iState) will already be set to TSendMsgState, so ReEnterCurrentState() will cause us to enter that state: void CGdpSmsSender::TSendMsgState::EnterL() { // Close the socket as it may already be open. iSender.iSocket.Close(); // Open a socket TInt ret = iSender.iSocket.Open(iSender.iResMan.iSocketServer, KSMSAddrFamily, KSockDatagram, KSMSDatagramProtocol); User::LeaveIfError(ret); // Bind to SMS port TSmsAddr smsAddr; smsAddr.SetSmsAddrFamily(ESmsAddrSendOnly); iSender.iSocket.Bind(smsAddr); // Open a write stream on the socket and stream our message. RSmsSocketWriteStream writeStream(iSender.iSocket); TRAP(ret, writeStream << *(iSender.iSmsMsg)); User::LeaveIfError(ret); // message has not been sent at this point TRAP(ret, writeStream.CommitL()); User::LeaveIfError(ret); // Send the message iSender.iSocket.Ioctl(KIoctlSendSmsMessage, iSender.iStatus, &iSender.iPkgBuf, KSolSmsProv); iSender.SetActive(); } To initiate a send, I first close various resources that might already be open, reopen them, and then open a socket using the SMS protocol. The socket server is already opened by the resource manager. We specify that we are only sending an SMS when binding to the socket. Next we open an RSmsSocketWriteStream object on the open socket, output the CSmsMessage, and commit the write. At this point however the message has not been sent. We need to make an asynchronous call on the socket to complete the send. If this fails and leaves, the appropriate sender state machine error handler is invoked: CGdpStateMachine::TState* CGdpSmsSender::ErrorOnStateEntry (TInt /*aError*/) { return NULL; // Give up! } If the state entry completes successfully, however, the following code will be invoked by the RunL(): CGdpStateMachine::TState* CGdpSmsSender::TSendMsgState::CompleteL() { RDebug::Print(_L("Message sent!!")); delete iSender.iSmsMsg; iSender.iSocket.Close(); // Let handler know message sent successfully iSender.iHandler->SendComplete(KErrNone); return NULL; // Last state so return NULL } This simply releases the resources we have used to send the message and notifies the handler that we have successfully sent the message. Notice how we specify the next state to enter as NULL as we have completed the process. If the send fails, the ErrorL() function is invoked: CGdpStateMachine::TState* CGdpSmsSender::TSendMsgState::ErrorL(TInt aCode) { // Let handler know the reason for sent failure iSender.iHandler->SendComplete(aCode); User::Leave(aCode); return NULL; // Never actually hit } The sender state machine's error handler performs the following: CGdpStateMachine::TState* CGdpSmsSender::ErrorOnStateExit(TInt /*aError*/) { Reset(); if ( iRetries < 0) return NULL; return CurrentState(); // Force re-entry to initial state } As asynchronous errors often indicate a communications error, we attempt to reset the state machine and do a limited number of retries. If, for some reason, the operation is cancelled while the send is taking place (generally because the user chose to quit, and hence Close() has been called), the following will be called: void CGdpSmsSender::TSendMsgState::Cancel() { if (iSender.iSocket.SubSessionHandle()) iSender.iSocket.CancelIoctl(); } Receiver Receiving an SMS message is a bit more complex than sending an SMS message. Once the client issues a ReceiveAllL(), we need to enter a wait state, and wait for SMS messages containing our GDP SMS specific pattern. In fact, this is all that we can do as all other SMS messages will be consumed by the messaging application. Once received, we can read the SMS message and then go back into the wait state and wait for the next GDP specific SMS message (Figure 20.7). Figure 20.7 Note: If the SMS message is received before the CGdpSmsReceiver is Active, the message will be collected by the messaging app and will no longer be available to the GDP application. This requires the following asynchronous requests:  Issue an RSocket::Ioctl() call on an SMS socket to find a matching pattern on incoming SMS messages.  Issue an RSocket::Ioctl() call on an SMS socket to read an SMS message. This directly tells us the states that are required, as shown in the state diagram above. Issuing the wait for a GDP SMS message works like this: void CGdpSmsReceiver::TWaitState::EnterL() { // Close the socket, as it may already be open. iReceiver.iSocket.Close(); // Open a socket User::LeaveIfError(iReceiver.iSocket.Open( iReceiver.iResMan.iSocketServer, KSMSAddrFamily, KSockDatagram, KSMSDatagramProtocol)); // Set the pattern to search for in incoming SMS messages. Messages, which do // not have our signature will be consumed by the Messaging Application. TSmsAddr smsAddr; smsAddr.SetSmsAddrFamily(ESmsAddrMatchText); smsAddr.SetTextMatch(KGdpSmsHeaderTag8()); User::LeaveIfError(iReceiver.iSocket.Bind(smsAddr)); // Wait for incoming messages iReceiver.iOctlResult()= KSockSelectRead; iReceiver.iSocket.Ioctl(KIOctlSelect, iReceiver.iStatus, &(iReceiver.iOctlResult), KSOLSocket); iReceiver.SetActive(); } First of all, as with TSendMsgState::EnterL() I close various resources that might already be open, reopen them, and then open a socket using the SMS. We then set the pattern match so that we receive only those messages matching the pattern and call an asynchronous control command on the socket to accept incoming SMS messages. Successful completion invokes the following: CGdpStateMachine::TState* CGdpSmsReceiver::TWaitState::CompleteL() { // Received a message so move to read state. return static_cast<TState*> (&iReceiver.iReadMsgState); } As we have a message matching our pattern, we simply move on to the TReadMsgState. void CGdpSmsReceiver::TReadMsgState::EnterL() { // Create an empty message and buffer for our incoming message. CSmsBuffer* buffer=NULL; buffer=CSmsBuffer::NewL(); iReceiver.iSmsMsg = CSmsMessage::NewL(iReceiver.iResMan.iFs, CSmsPDU::ESmsSubmit, buffer); // Read the message. RSmsSocketReadStream readstream(iReceiver.iSocket); TRAPD(ret, readstream >> *(iReceiver.iSmsMsg)); User::LeaveIfError(ret); // Let the socket know that we have read the message and it can be removed // from the message store. iReceiver.iSocket.Ioctl(KIoctlReadMessageSucceeded, iReceiver.iStatus, NULL, KSolSmsProv); iReceiver.SetActive(); } Here I create a CSmsBuffer and CSmsMessage to store our extracted SMS message; then I open an RSmsSocketReadStream object on the open socket and stream the SMS from the socket into the CSmsMessage. As we have collected and dealt with the message, we send an Acknowledge to the SMS Service Center so it doesn't attempt to resend it. On successful completion, we need to extract the contents of the message and pass this to the handler as follows: CGdpStateMachine::TState* CGdpSmsReceiver::TReadMsgState::CompleteL() { // Extract the message contents CSmsBuffer& smsbuffer = (CSmsBuffer&)iReceiver.iSmsMsg- >Buffer(); TInt len = smsbuffer.Length(); HBufC* hbuf = HBufC::NewLC(len); TPtr ptr = hbuf->Des(); // We are only interested in the message contents, not our pattern. smsbuffer.Extract(ptr, KGdpSmsPatternLen, len- KGdpSmsPatternLen); // Convert from unicode data and send to handler TBuf8<KGdpSmsSduMaxSize> buf; buf.Copy(*hbuf); iReceiver.iHandler->GdpHandleL(KNullDesC8, buf); // Cleanup CleanupStack::PopAndDestroy(); // hbuf; delete iReceiver.iSmsMsg; iReceiver.iSocket.Close(); [...]... also available for use in conjunction with the Wireless Developer Toolkit Symbian OS v6.0 The Nokia 92 00 Communicator Series SDK for Symbian OS v6.0 is available from Forum Nokia This enables development in Symbian OS C++ or Java for the Nokia 9 210 , 9 210 c, 9 210 i and 92 90 communicators Localized Chinese versions of the SDK are available too C++ developers will need to obtain Microsoft Visual C++ 6.0 Java... available for use in conjunction with the Wireless Developer Toolkit Symbian OS v6 .1 The Series 60 SDK for Symbian OS is available from Forum Nokia This enables development in Symbian OS C++ for the Nokia 7650, Nokia 3650 imaging phones and the N-Gage mobile game deck C++ developers need to obtain Microsoft Visual C++ 6.0 Alternatively, Forum Nokia is making available the Nokia Series 60 C++ Toolkit 1. 0,... following versions of Symbian OS are currently available Development languages other than Java and C++ are supported through other SDKs and SDK extensions Symbian OS v7.0 The UIQ SDK for Symbian OS v7.0 is available for download from Ericsson Mobility World This facilitates development in Symbian OS C++ or Java for the Sony Ericsson P800 and P802 smartphones Symbian OS C++ developers need to obtain... applications for Symbian OS phones is to obtain a software development kit (SDK) Symbian OS SDKs support development in both Java and C++ They provide binaries and tools to facilitate building and deployment of Symbian OS applications, full system documentation for APIs and tools PC-based emulation of Symbian OS phones Example applications with supporting documentation SDKs for the following versions of Symbian. .. will need JDK 1. 1.8, which is available for free download from Sun MIDP development is not currently supported for the 92 00 Series Communicator Symbian OS v5 Psion has a long history of using Symbian OS, and several leading PDAs still use Symbian OS v5 Current products include the netBook and the netPad Developers can make use of Symbian OS v5 SDKs and SDK extensions to target Psion PDAs in C++, Java or... Tools archive Symbian DevNet offers the following tools as an unsupported resource to all developers: Symbian OS SDK add-ons http://www .symbian. com/developer/downloads/v6sdks.html Symbian OS v5 SDK patches and tools archive http://www .symbian. com/developer/downloads/archive.html Symbian OS SDKs For the updates and links see http://www .symbian. com/developer/SDKs.html The starting point for developing... updates, and subscribe to the Symbian Community Newsletter for updates.http://www .symbian. com/developer Symbian OS developer tools For the latest see http://www .symbian. com/developer/tools.html Symbian DevNet and its partners offer various tools: AppForge AppForge development software integrates directly into Microsoft Visual Basic, enabling you to immediately begin writing multiplatform applications using... Metrowerks offer the following products supporting Symbian OS development: CodeWarrior Wireless Studio, Nokia 92 00 Communicator Series Edition CodeWarrior Development Tools for Symbian OS Professional Edition CodeWarrior Development Tools for Symbian OS with Personal- Java Technology http://www.metrowerks.com Sun Microsystems Sun provides a range of tools for developing Java 2 Micro Edition applications... Borland C++ Mobile Edition, an extension to their popular C++ Builder, with a Borland-compatible build of the Series 60 emulator and associated binaries For Java MIDP development, the Nokia Series 60 MIDP SDK Beta 0 .1 for Symbian OS is available from Forum Nokia Java developers will also need Sun's J2SE SDK, version 1. 3 or higher, and Wireless Developer Toolkit, both of which are available for free... to allow rapid application development, with provision for on-target application creation OPL was included in all open Symbian OS products up to and including Symbian OS v5 and is now open source for the Nokia 92 00 OPL development for Symbian OS v5 requires the v5 OPL SDK The SDK includes documentation, tools, example code and a Windows emulator for testing No further tools are required If you are already . accepted. 20.3 .1 Symbian OS Support for Bluetooth Access to either RFCOMM or L2CAP from Symbian OS is via the socket server client APIs. The socket server has a plug-in framework for which BT.PRT. by the Bluetooth Special Interest Group (SIG) in 19 98. With an operating range of approximately 10 m, it is an ideal technology for sharing information between devices. It also does not suffer. // Port 11 for GDP iAddr.SetPort(port); // Now set the socket to listen on the right port TInt ret = iListenSocket.Bind(iAddr); // If the Bind() didn't succeed we're outta

Ngày đăng: 13/08/2014, 08:21

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan