Examensarbete LITH-ITN-ED-EX--06/005--SE

Waveform Development using Software Defined Radio

Thomas Sundquist

2006-04-25

Department of Science and Technology Institutionen för teknik och naturvetenskap Linköpings Universitet Linköpings Universitet SE-601 74 Norrköping, Sweden 601 74 Norrköping LITH-ITN-ED-EX--06/005--SE

Waveform Development using Software Defined Radio Examensarbete utfört i Elektronikdesign vid Linköpings Tekniska Högskola, Campus Norrköping Thomas Sundquist

Handledare Annica Söderlund Examinator Ole Pedersen

Norrköping 2006-04-25 Datum Avdelning, Institution Date Division, Department

Institutionen för teknik och naturvetenskap 2006-04-25

Department of Science and Technology

Språk Rapporttyp ISBN Language Report category ______Svenska/Swedish Examensarbete ISRN LITH-ITN-ED-EX--06/005--SE x Engelska/English B-uppsats ______C-uppsats Serietitel och serienummer ISSN x D-uppsats Title of series, numbering ______

______

URL för elektronisk version

Titel Title Waveform Development using Software Defined Radio

Författare Author Thomas Sundquist

Sammanfattning Abstract Software Defined Radio (SDR) is a conception of implementing radio functions in computer software, instead of having electronics performing the functions. This thesis aims to compare two different ways of implementing these functions, or waveforms. The Software Communications Architecture (SCA) is an open standard developed by the United States Department of Defense. It uses a CORBA interface environment to make waveform applications interoperable and platform independent. This method of developing SDR is compared to an open-source initiative going by the name GNU Radio. Two waveform applications are developed, one transmitter using SCA, and one receiver using GNU Radio. The analog radio interface is simulated using the sound cards of two regular PCs. The development is done using the C++ and Python programming languages. This thesis examines pros and cons of the two SDR methods, as well as performing studies of Software Defined Radio in general.

Nyckelord Keyword SDR, SCA, GNU Radio, CORBA, IDL, XML Upphovsrätt

Detta dokument hålls tillgängligt på Internet – eller dess framtida ersättare – under en längre tid från publiceringsdatum under förutsättning att inga extra- ordinära omständigheter uppstår. Tillgång till dokumentet innebär tillstånd för var och en att läsa, ladda ner, skriva ut enstaka kopior för enskilt bruk och att använda det oförändrat för ickekommersiell forskning och för undervisning. Överföring av upphovsrätten vid en senare tidpunkt kan inte upphäva detta tillstånd. All annan användning av dokumentet kräver upphovsmannens medgivande. För att garantera äktheten, säkerheten och tillgängligheten finns det lösningar av teknisk och administrativ art. Upphovsmannens ideella rätt innefattar rätt att bli nämnd som upphovsman i den omfattning som god sed kräver vid användning av dokumentet på ovan beskrivna sätt samt skydd mot att dokumentet ändras eller presenteras i sådan form eller i sådant sammanhang som är kränkande för upphovsmannens litterära eller konstnärliga anseende eller egenart. För ytterligare information om Linköping University Electronic Press se förlagets hemsida http://www.ep.liu.se/

Copyright

The publishers will keep this document online on the Internet - or its possible replacement - for a considerable time from the date of publication barring exceptional circumstances. The online availability of the document implies a permanent permission for anyone to read, to download, to print out single copies for your own use and to use it unchanged for any non-commercial research and educational purpose. Subsequent transfers of copyright cannot revoke this permission. All other uses of the document are conditional on the consent of the copyright owner. The publisher has taken technical and administrative measures to assure authenticity, security and accessibility. According to intellectual property law the author has the right to be mentioned when his/her work is accessed as described above and to be protected against infringement. For additional information about the Linköping University Electronic Press and its procedures for publication and for assurance of document integrity, please refer to its WWW home page: http://www.ep.liu.se/

© Thomas Sundquist i

Abstract

Software Defined Radio (SDR) is a conception of implementing radio functions in computer software, instead of having electronics performing the functions. This thesis aims to compare two different ways of implementing these functions, or waveforms. The Software Communications Architecture (SCA) is an open standard developed by the United States Department of Defense. It uses a CORBA interface environment to make wave- form applications interoperable and platform independent. This method of developing SDR is compared to an open-source initiative going by the name GNU Radio. Two waveform applications are developed, one transmitter using SCA, and one receiver using GNU Radio. The analog radio interface is simulated using the sound cards of two regular PCs. The development is done using the C++ and Python programming languages. This thesis examines pros and cons of the two SDR methods, as well as performing studies of Software Defined Radio in general.

Keywords: SDR, SCA, GNU Radio, CORBA, IDL, XML ii iii

Preface

This is a masters thesis on Waveform Development using Software Defined Radio written by Thomas Sundquist and Mansour Fanni. The thesis and development work were performed during the summer and autumn of 2005 at Ericsson Microwave Systems in Gothenburg, Swe- den.

Thesis outline This thesis is split into 7 chapters:

Chapter 1 is an introduction to the thesis.

Chapter 2 deals with Software Defined Radio (SDR) in general.

Chapter 3 is all about CORBA.

Chapter 4 examines the SCA on a deeper level.

Chapter 5 looks into GNU Radio.

Chapter 6 introduces the MATH waveform.

Chapter 7 reflects our conclusions.

There are also several appendixes. Besides the complete source code to our applications, there is an installation guide and a document that deals with platform-specific problems that occurred during our development time. The latter might come in handy when trying to compile and use our applications.

Acknowledgement This thesis wouldn’t have made it this far without the support of several people to whom we would like to offer our thanks. Our supervisors at Ericsson Microwave Systems, Annica Soderlund,¨ Daniel Guldbrand and Hakan˚ Berggren, for helping us and guiding us through the thesis work. Ole Pedersen, our examiner at Linkoping¨ University, who has read and criticized our report and given us useful tips and pointers. And last but definitely not least, we would like to thank our families and friends, who have supported us in many ways throughout the project. iv v

Contents

Abstract i

Preface and Acknowledgement iii

1 Introduction 1 1.1 Background...... 1 1.2 Objectives...... 1 1.3 Methods...... 1

2 Software Defined Radio 3 2.1 Introduction...... 3 2.1.1 Waveforms ...... 3 2.1.2 SoftwareDefinedRadio ...... 3 2.2 GNURadio...... 4 2.3 Software Communications Architecture ...... 5

3 CORBA 7 3.1 CORBAingeneral ...... 7 3.1.1 IDL...... 7 3.1.2 PortableObjectAdapter ...... 9 3.1.3 NamingService...... 9

4 Software Communications Architecture 11 4.1 Introductionandabstract ...... 11 4.2 CoreFramework ...... 12 4.2.1 Base Application Interfaces ...... 12 4.2.2 Framework Control Interfaces ...... 13 4.2.2.1 DomainManager ...... 14 4.2.2.2 Application ...... 14 4.2.2.3 ApplicationFactory ...... 14 4.2.2.4 Devices and DeviceManager ...... 14 4.3 eXtensibleMarkupLanguage...... 15 4.4 DomainProfile ...... 15 4.5 SCAandCORBA...... 17 4.6 SCAwaveformdevelopment ...... 18 4.6.1 Development tools ...... 18 4.6.2 TheAPIofSCA ...... 18 vi

5 GNU Radio 21 5.1 Overview ...... 21 5.2 SDR Construction using GNU Radio ...... 21 5.3 Creating your own building block ...... 22 5.3.1 SWIG...... 22 5.3.2 Boost ...... 22 5.3.3 Naming Conventions ...... 22 5.3.4 Muchmoretoknow ...... 23 5.3.5 TheC++Class ...... 23 5.4 Asimpleexample...... 24

6 Implementation of the MATH Waveform 27 6.1 Introduction...... 27 6.2 SCAimplementation ...... 28 6.2.1 The beginning steps ...... 28 6.2.2 The MATH implementation ...... 29 6.2.3 Functionality ...... 30 6.2.4 Signalingsystem ...... 31 6.3 GNURadioimplementation ...... 32 6.3.1 Firstattempt ...... 32 6.3.2 Two signal-flow-graphs ...... 33 6.3.3 The actual implementation ...... 33 6.3.3.1 TheC++code ...... 34 6.3.3.2 The Python code ...... 34

7 Conclusions 35 7.1 Developing waveforms using SCA ...... 35 7.1.1 Benefitsandadvantages ...... 35 7.1.2 DisadvantagesofSCA ...... 36 7.1.3 Conclusions about the SCA ...... 37 7.2 Developing waveforms using GNU Radio ...... 37 7.2.1 Advantages of GNU Radio ...... 37 7.2.2 Disadvantages and drawbacks ...... 38 7.3 Comparison of the two methods ...... 39

References 41

Index 43

Appendixes

A Platform-related issues 47

B Installation Guide 51

C MATH GNU Radio Python application 53

D MATH SCA application 59 1

Chapter 1

Introduction

1.1 Background

The possibility to change waveform in a radio by using software or the ability to use the same software in different platforms have lately become more and more interesting. This technique is called Software Defined Radio. In response to this interest a standardized architecture for creating software waveforms has been developed in the United States by the Department of Defense. This architecture is known as the Software Communications Architecture. There are other methods of developing software waveform applications. One of them is GNU Radio, which is an open-source initiative.

1.2 Objectives

The purpose of this master thesis is to compare waveform development using SCA versus development using GNU Radio. The comparison will use the sound cards of two regular PCs to simulate the radio interface. Pros and cons of these two ways of deploying waveforms will be studied, and general issues regarding waveform developing in software is to be examined. The thesis includes studies in CORBA, XML, C++ and Python.

1.3 Methods

Before starting to develop a waveform using SCA or GNU Radio, a lot of studying has to be done. Studies of the SCA specification and Developer’s Guide are needed to learn more about SCA and how to use it for waveform development. The understanding of CORBA is essential for understanding how SCA waveforms are developed and how the SCA Core Framework works, thus a big portion of time is dedicated to studies of CORBA. XML is used to some extent in SCA development, so XML have to be learned. Besides touching up on C++ for the actual development work in both SCA and GNU Radio, GNU Radio uses the powerful scripting language Python which also needs a portion of time to learn and comprehend. Then the actual implementation can be started. The project aims to create an SDR trans- mitter and receiver using SCA and GNU Radio, and then transmit some sort of signal across two regular PC sound cards. 2 3

Chapter 2

Software Defined Radio

This chapter is an introduction to Software Defined Radio (SDR) in general. In section 2.3 and 2.2 two different ways to implement SDR are introduced.

2.1 Introduction

The “normal” way of implementing waveforms and radio functions is having hardware-based systems do all the work. Generation, modulation/demodulation, filter functions, up/down- conversion of frequencies, everything is done with electronics in some way. Therefore, there are some limitations to what a specific machine can do. For example, your normal FM-radio in your kitchen knows how to do exactly one thing, convert FM radio waves into sound you can listen to. Now imagine a radio technology that can turn your kitchen radio into a GSM telephone, or a GPS receiver, or maybe a satellite communications terminal. Or why not a garage door opener? That’s exactly the opportunities that emerge with software radios!

2.1.1 Waveforms There are a lot of references to the word waveform in this thesis, so we’ll start by explaining what we mean when we talk about waveforms. A waveform can be described as a radio function, everything that is used to describe a spe- cific radio signal is included in the waveform conception. Generation, modulation, filtration etc, all the different components of a radio function are put together and form the conception waveform. For instance, WCDMA (Wideband Code-Division Multiple-Access) is one of the main technologies for the implementation of third-generation (3G) cellular systems. This is an example of a waveform. GSM or FM would be other examples of waveforms. Hence, we do not only talk about the actual electromagnetic waves when we refer to a waveform, as one might think when first encountering the word.

2.1.2 Software Defined Radio This radio technology is called Software Defined Radio (SDR), where almost all radio func- tions are moved out of hardware electronic circuits into software. The idea is to get the soft- 4 Chapter 2. Software Defined Radio ware source code as close to the antenna as possible. Waveforms are generated, encoded, modulated, filtered and processed in computer software. So what’s so great about this? At a first glance it might not seem very exciting, but there are a lot of benefits in the world of software radio.

• The ability to change waveform and function on-the-fly. One general-purpose device can be configured into whatever kind of radio you are in need of at the moment. GPS receiver one minute, cordless phone the next. Only the imagination sets the limits.

• Quick and easy upgrading with new and enhanced features. Upgrading the software can be done over the air.

• Cost-effective solutions. When new waveforms are required in a system, there is no need to purchase new hardware equipment, just upload the new software remote and you have a fully functional system with completely new features.

• Receive and broadcast multiple channels at the same time.

• Portability. An open standard architecture makes it possible for different kinds of com- municators to talk to each other. It’s not uncommon today that different types of gov- ernment organizations such as police and fire departments from different areas can’t communicate with each other due to the fact that they are using different types of radio systems. With SDR the communication devices can reconfigure themselves and thus “learn another language”.

The basic idea of SDR is shown in Figure 2.1. If we look at the receiving part, there is an antenna, an RF front end, an analog-to-digital converter, and then the actual software code. The analog-to-digital converter (ADC) is the link between the analog world of continuous signals and the digital world where the signals are discrete. The radio signal is usually broad-casted in high frequencies, several hundred or thousands of MHz, so the job for the RF front end is to translate the signal down to a lower frequency that the ADC is able to handle. After the signal is digitized, it’s all up to the software to do the actual work.

2.2 GNU Radio

GNU Radio 1 is a free open-source collection of software, that combined with minimal hard- ware can be used to receive and transmit waveforms. GNU Radio comes with a huge collection of ready-to-use filters, modulators, demodulators, signal sources and other tools that can be used when constructing and/or receiving signals and waveforms. GNU Radio also comes with software tools such as a spectrum analyzer and an oscilloscope. And since it’s a truly , if there’s something missing in this vast collection of tools, anyone can develop new functions and modules. More of how this is done is described in chapter 5. An article [12] published in Linux Journal magazine describes the GNU Radio project more in detail.

1http://www.gnu.org/projects/gnuradio/ 2.3. Software Communications Architecture 5

Antenna

AD RF Front End Software Converter

Receiving software radio

Antenna

DA RF Front End Software Converter

Transmitting software radio

Figure 2.1 Basics of SDR

Several projects have been developed using GNU Radio including a complete HDTV re- ceiver and broadcaster and a multichannel FM receiver capable of listening to several channels at the same time. The latter is an example of the strength of software radio.

2.3 Software Communications Architecture

In 1997 the United States Department of Defense (DoD) initiated the Joint Tactical Radio System (JTRS) program, as a way to try and solve the issue of a programmable, modular, multi-band, multi-mode radio, that would eventually replace over 200 different radio types within the DoD. In late 1998, the first step towards the Software Communications Architecture (SCA) was taken. The SCA is a non-proprietary, open architecture framework, to help promote the devel- opment of interoperable software and hardware. The SCA is not a system specification, as it is intended to be implementation independent, but rather a set of design constraints. If a developer designs a system according to the these design rules, his system will be portable with other SCA implementations regardless of what or hardware that imple- mentation is based on. The software structure of the SCA is called the Operating Environment, and consists of the following components:

- a Core Framework, this is the collection of interfaces and services that provide an ab- straction of the underlying layers for software application designers. The interfaces are described using CORBA IDL, which is described in chapter 3, section 3.1.1. 6 Chapter 2. Software Defined Radio

- a CORBA middleware that is used for all communications within the waveform. A middleware can be described as the “glue” between software components or between software and the network.

- a POSIX-compliable operating system. We have used the GNU/Linux operating system during our work.

Figure 2.2 SCA Software Structure

Figure 2.2 shows the relations between the operating environment and the waveform. The application layer at the very top is where the actual SDR components are, i.e. the “waveform” layer. Beneath is the operating environment: the operating system with underlying hardware buses at the bottom layer and the Core Framework and the CORBA middleware on top of that. The CORBA middleware and Core Framework are described more in detail in chapters 3 and 4. Especially, understanding how CORBA and the SCA waveform connect to each other and what an SCA waveform really is, can be read about in chapter 4, section 4.5. 7

Chapter 3

CORBA

Since CORBA is such an important component in the SCA, this chapter explains the essence of CORBA and what is to be understood before reading chapter 4.

3.1 CORBA in general

CORBA is an acronym for Common Object Request Broker Architecture, and is a standard for producing client/server middleware in a distributed environment. The CORBA standard is created and controlled by the Object Management Group (OMG). The CORBA mechanism allows programs to be running on different machines and written in different programming languages while safely (and portably) exchanging data and the CORBA mechanism is ideal for classic client/server applications. The ORB (Object Request Broker) is the piece of software running on a machine that handles all server/client requests. The protocol used by CORBA to communicate is the General Inter-ORB Protocol (GIOP). The GIOP maps ORB requests to different network transports, and one such implementation is the Internet Inter-ORB Protocol, IIOP. An important issue for object interoperability is how ORBs address, or locate, objects. An object reference can be thought of as a trustworthy name that always symbolizes a specific object. These references are standardized for all ORBs. Thus, any ORB can invoke opera- tions and calls to objects located with other ORBs. The way CORBA handles this is by the Interoperable Object Reference (IOR), which is a sequence of characters that specifies a single CORBA object wherever in the world it is located.

3.1.1 IDL CORBA uses OMG’s Interface Definition Language (IDL) to specify the interfaces that ob- jects will present to the world. CORBA then specifies a ”mapping” from IDL to a specific implementation language like C++ or Java. Any client that wants to invoke an operation on a CORBA server object, must use the object’s IDL interface to specify which operation it wants to perform. IDL is not a programming language - it’s great for defining interfaces, but it doesn’t have the constructs you’d need to write a program. The IDL interface defines the contract between 8 Chapter 3. CORBA the client and server parts of your application, specifying what operations and attributes are available. The programmer then uses an IDL compiler to generate application code, skeletons for the server part, and stubs for the client part. The stubs and skeletons run on top of an Object Request Broker (ORB), and they work as proxies for servers and clients, respectively. This way, the client and server can be written in different languages and/or be running on different platforms and be able to communicate with each other in a safe, scalable manner [5]. Every CORBA server object has a unique object reference, and there are several ways of which the client can get a hold of this reference. Once obtained, the client can invoke operations on the server object. The invocation is really invoked on the client stub, which uses the ORB to forward the request to the servant object, through the server skeleton. Figure 3.1 shows a model of this.

Figure 3.1 Client-server model in CORBA using stubs and skeletons.

The ORB block contains the necessary means to pass over the request from client to server. Usually the client and server are not connected to the same ORB, and the GIOP/IIOP protocol is used to forward the request. A modification showing this is pictured in figure 3.2. This is all transparent from the client and server view. All the client needs is the reference to the servant, and then the ORBs handle the technical stuff such as load balancing, resource control and error handling of the requests.

Figure 3.2 The inter-ORB communication using GIOP/IIOP. 3.1. CORBA in general 9

A simple example of IDL is shown below. The interface Modulator has one operation called ModulateData which takes one input argument and returns nothing (void), and has one attribute called ModulatorStatus. It also inherits the Resource and Port interfaces from the Core Framework.

interface Modulator : CF::Resource, CF::Port { void ModulateData(in double incoming_data);

attribute int ModulatorStatus; }

There are a lot of ORB implementations, for this masters thesis we have used the TAO ORB [11] which has real time capabilities. TAO is a real-time ORB based on the SunSoft IIOP protocol engine. TAO is targeted for applications with deterministic and statistical Quality of Service (QoS) requirements, as well as best effort requirements.

3.1.2 Portable Object Adapter The Portable Object Adapter (POA) is a way of making implementation objects available to the ORB for servicing requests. All CORBA calls on a CORBA object goes through the POA. The POA maps a CORBA object ID to the actual implementation object. Upon a server object initialization, it registers itself with the POA. This can be seen in our source code in appendix D.

3.1.3 Naming Service The OMG Naming Service [7] is one of CORBA’s standardized services. The Naming Service provides the principal mechanism through which most clients of an ORB-based system locate objects that they intend to use. The basic function of the naming service is the association of names with object references. A server object creates associations between a name and its object reference, and registers this information in the Naming Service. Then a client that knows the name of an object can retrieve its object reference by querying the Naming Service. This can also be seen in our source code. 10 11

Chapter 4

Software Communications Architecture

This chapter features a more detailed description of the SCA environment, the Core Framework and the waveform components, with emphasis on the components that we have used for this thesis. The Domain Profile is described, and the chapter ends with an introduction on how to develop a waveform application.

4.1 Introduction and abstract

SCA is designed to be an open, standardized architecture providing interoperability, easy in- sertion of new technology, quick upgrade capability, software reuse and scalability. When designing the structure of an SCA compliant system, all these factors should be kept in mind. An SCA waveform or Application consists of one or more software Resources and/or hard- ware Devices. A Device is a type of Resource used by applications as software proxies for actual hardware devices. The Application is created in an ApplicationFactory, usually by the DomainManager. Every component in an SCA compliant waveform inherits from the Core Framework in- terfaces. These interfaces are described in CORBA IDL language, and then compiled into the programming language of your choice. The Domain Profile is a set of XML files to describe the characteristics of the system, the different interfaces that it is composed of and their functional capabilities and inter-dependencies. The Domain Profile is managed by the DomainManager. Legacy software components that don’t have CORBA support can be incorporated in an SCA system by the use of CORBA adapters, which are proxies to wrap the functionality of the component in the CORBA environment. Figure 4.1 shows the relationship between the waveform or Application and the Operating Environment which consists of the CF, the CORBA middleware, and the operating system. Although the SCA uses the CORBA middleware for its software bus, the application layer can reach the OS by other means. However, waveform access to the OS is highly restricted. In section 4.6 the SCA is described from the application developers point of view. 12 Chapter 4. Software Communications Architecture

Figure 4.1 Relationship between SCA structures

4.2 Core Framework

As mentioned in chapter 2, section 2.3, the Core Framework (CF) is one of the key components in an SCA system. The CF consists of:

• Base Application Interfaces (Port, LifeCycle, TestableObject, PropertySet, PortSupplier, ResourceFactory and Resource) that can be used by all software applications.

• Framework Control Interfaces (Application, ApplicationFactory, DomainManager, De- vice, LoadableDevice, ExecutableDevice, AggregateDevice and DeviceManager) that provide control of the system.

• Framework Services Interfaces (File, FileSystem, FileManager and Timer) that support both core and non-core applications.

• A Domain Profile that describes the properties of hardware devices (Device Profile) and software components (Software Profile) in the system.

4.2.1 Base Application Interfaces The Base Application Interfaces are the building blocks used to create an SCA waveform. These interfaces are Port, LifeCycle, TestableObject, PortSupplier, PropertySet, Resource and ResourceFactory. 4.2. Core Framework 13

An SCA system is made by several components, these different parts communicate with each other through ports. The Port interface provides two operations to set up communica- tions, connectPort() and disconnectPort(). Components that provide ports inherits from the PortSupplier interface which defines the getPort() operation. This is used to ob- tain a specific port from a component. The LifeCycle interfaces defines two operations, initialize() and releaseObject(). initialize() is used to set a component to a known initial state, and releaseObject() tears a component down when it’s not to be used any more. TestableObject is inherited by a component to run built-in tests. The system designer can use the runTest() operation to test the component, for example to search for errors within the component. The PropertySet interface is used to access component properties/attributes. It defines two operations: configure(), which makes runtime configuration possible, and query(), to allow a component to be queried of its properties. Every software component in an SCA waveform shall inherit the Resource interface. This in turn inherits from LifeCycle, TestableObject, PortSupplier and PropertySet. Two operations are also provided, start() and stop(), to be able to start and stop the component. A Resource can be created by a ResourceFactory, and if it is, the same ResourceFactory shall be used to tear down the Resource. The ExecutableDevice interface can be used as an alternative way to create a Resource. Figure 4.2 shows the Resource interface and its inheritances depicted in the Unified Mod- eling Language (UML). For more information on UML see [15].

LifeCycle PropertySet PortSupplier TestableObject initialize() configure() getPort() releaseObject() query() runTest()

Resource identifier:string start() stop()

Figure 4.2 Resource Interface UML Diagram

4.2.2 Framework Control Interfaces The Framework Control Interfaces consist of DomainManager, ApplicationFactory, Appli- cation, Device, LoadableDevice, ExecutableDevice, AggregateDevice and DeviceManager. These interfaces can be grouped as Domain Management Interfaces and Device Manage- ment Interfaces. Domain Management Interfaces are DomainManager, ApplicationFactory and Application. These three interfaces are coupled together and must always be delivered as 14 Chapter 4. Software Communications Architecture a complete domain management implementation. They manage registration/deregistration of applications and devices within the domain, and also controlling of applications. The Device Management Interfaces are Device, LoadableDevice, ExecutableDevice, AggregateDevice and DeviceManager. The DeviceManager creates and controls the Device interfaces, which act as proxies for actual hardware devices in the SCA environment.

4.2.2.1 DomainManager

The DomainManager manages a set of available hardware devices and applications. It is responsible for the set-up and shut-down of Applications, Devices, Services and DeviceM- anagers. External applications such as a user interface can obtain a list of the Applications, Services and Devices through the DomainManager. Built-in-tests are also managed by the DomainManager. These operations increase the scalability of an SCA system by allowing runtime insertion and extraction of components.

4.2.2.2 Application

Waveforms are defined as Applications in an SCA system. The Application interface provides the Domain Management interface for the control and configuration of an instantiated appli- cation in the domain. A created application instance contains Resource components and may also contain non-CORBA components. The Application inherits the Resource interface, and delegates it’s Resource operations to the Application’s Assembly Controller.

4.2.2.3 ApplicationFactory

The ApplicationFactory interface provides the Domain Management interface to request the creation of a specific type of Application in the domain. The type of Application created and its components is determined by the Software Assembly Descriptor file, which is described in section 4.4. Each Application has an ApplicationFactory of its own.

4.2.2.4 Devices and DeviceManager

Actual hardware devices are represented as Devices in an SCA system. The Device interface inherits the Resource interface and adds additional capacity and state operations. LoadableDe- vice adds the capability to load and unload files on a particular device. The ExecutableDevice extends the LoadableDevice with the capability to execute and terminate processes on a de- vice. If the designer wants to create and run a Resource on a Device, this is the way go to. Finally, AggregateDevice can be looked upon as a collection of Devices, with operations to add and remove a device from the collection. The DeviceManager is responsible for controlling and managing Devices and services, and it has operations for registering and unregistering. It is not a factory, so it cannot initiate new Devices. There can exist several DeviceManagers at once, each controlling a number of Devices. Upon creation of the DeviceManager several things happen. The DeviceManager use the Device Configuration Descriptor file to discover the services to be deployed and Devices to be 4.3. eXtensible Markup Language 15 created for this DeviceManager. Then, it creates a FileSystem and mounts it to the Domain- Manager’s FileManager. Finally, the DeviceManager registers itself with the DomainMan- ager. Figure 4.3 shows the sequence diagram for this scenario.

Boot Up : DeviceManager : XML Parser : Device : DomainManager

1: create 2: create FileSystem

3: Parse DCD and SPD files

4: launch Device

5: registerDevice(in Device)

6: initialize()

7: configure(in properties)

launch, registerDevice, initialize and configure are 8: registerDeviceManager(in DeviceManager) performed for each Device in the system.

Figure 4.3 Sequence Diagram for DeviceManager Startup

4.3 eXtensible Markup Language

Properties, capabilities, dependencies and assembly of an SCA system is made with the eX- tensible Markup Language (XML). XML was developed by an XML Working Group formed under the oversight of the World Wide Web Consortium (W3C) in 1996. XML is a subset of SGML, the Standard Generalized Markup Language. XML can be used to describe data components, records and other data structures - even complex data structures. XML is a markup language much like HTML. It is extensible because it is not a fixed format like HTML (which is a single, predefined markup language). Instead, XML is actually a metalanguage, a language for describing other languages which lets you design your own markup languages for limitless different types of documents. To describe a language in XML, a Document Type Definition (DTD) is used. The DTD specifies what kind of data and attributes a document consists of, and is referenced at the top of an XML document. [16]

4.4 Domain Profile

The SCA specification requires portable software components to provide common information called a Domain Profile. The domain management functions use the component deployment information expressed in this Domain Profile. The information is used to start, initialize, and maintain the applications that are installed into the SCA-compliant system. 16 Chapter 4. Software Communications Architecture

The Domain Profile consists of a set of XML files. These files describe the components that make up an SCA system, their identity, capabilities, properties and inter-dependencies of each other. All of the descriptive data about a system is expressed in the XML vocabulary. Figure 4.4 portrays the relationships between the different parts of the Domain Profile in SCA.

Green Red Domain Profile

0..n 0..n <> <> Device Configuration Descriptor Software Assembly Descriptor 1

1 DomainManager 1 Configuration Descriptor

1

<> Profile Descriptor 1..n 1 1..n <> <>

Software Package Descriptor 1 Profile Descriptor

0..n 0..n 0..1

<> 0..n <> <>

Device Package Descriptor Properties Descriptor 0..n Software Component Descriptor

Figure 4.4 Domain Profile Descriptor

Software Package Descriptor The Software Package Descriptor (SPD) is an element of the Domain Profile that identifies one or more software component implementations. General information about a software pack- age, such as the name, author, property file, implementation code information and hardware and/or software dependencies are contained in a Software Package Descriptor file. An SPD is associated with one or more Software Component Descriptors.

Properties Descriptor Basically the Properties Descriptor File is the initial configuration file which contains the detailed settings for a component, and/or attributes for a device. These settings will be used by a CF Resource component’s configure()(), query()(), and runTest() operations. The reference to a component’s Properties Descriptor is obtained from the SPD file.

Software Component Descriptor The Software Component Descriptor (SCD) is an element of the Domain Profile that contains information about a specific SCA software component (CF Resource, CF ResourceFactory, CF Device). The SPD can contain several references to one or more Software Component Descriptors. For instance, there can be more than one implementation of a certain component. They can each be described in their own SCD, and then referenced with different IDs in the SPD. 4.5. SCA and CORBA 17

Software Assembly Descriptor

The Software Assembly Descriptor (SAD) is the element of the Domain Profile that contains information about the components that make up an application. The SAD describes how the different components of an Application are deployed and interconnected, and is associated with one or more Software Package Descriptor files.

Device Configuration Descriptor

The Device Configuration Descriptor provides the means of describing the hardware compo- nents (Devices) within an application and the characteristics of a CF DeviceManager. It also contains information on how to obtain the DomainManager object reference.

Domain Configuration Descriptor

Finally, the Domain Configuration Descriptor is the file which describes the DomainManager. It contains references to the DomainManagers SPD file, which in turn can be used to de- scribe the CF DomainManager implementation and to specify the uses ports for the domain’s services, for example the the DomainManager’s Log service.

4.5 SCA and CORBA

The Core Framework interfaces are expressed in CORBA IDL [9]. When implementing a waveform, all components which constitute the waveform are also described in CORBA IDL. As written in chapter 3, section 3.1.1, IDL is a language that defines interfaces. So basically, an SCA waveform is a bunch of interfaces. When compiling the CORBA IDL, server skeletons and client stubs are created. This means, on a deeper level, that all the waveform components such as Resources and Devices are actually CORBA servants and/or clients! The “and/or” has to be emphasized. A component can be (usually is) both server and client at the same time. It can be illustrated with an example. Take some components, A, B and C. A has an interface that B is connected to. B uses the interface provided by A. This makes A a CORBA servant and B the CORBA client that connects to the servant. On the other hand, C has an interface A is connected to. In this case, C is the server and A the client. Thus, A is both server and client at the same time. The various components of the waveform uses the CF Port interface (remember this is also a CORBA IDL interface) to make connections with each other. The terms uses port and provides port are commonly used in SCA development. A uses port requests data or service from another component, while a provides port returns requested data or performs a requested service. Under this model, software assumes the role of a CORBA client when it is calling through a uses port, and the role of a CORBA servant when it is answering at a provides port [13]. 18 Chapter 4. Software Communications Architecture

4.6 SCA waveform development

When developing an SCA waveform, the operating environment (Core Framework, CORBA middleware and operating system) is provided as the base structure. The only thing the devel- oper should need to be concerned about is the top layer in figure 2.2 on page 6, the application layer.

4.6.1 Development tools There exist several development tools and toolkits for the SCA environment. Having access to such a toolkit would probably making development of SCA compliant waveforms a lot easier in comparison to having to do most of the structural work on your own, as we did in this thesis. Examples of companies delivering such tools are Prismtech1 and Pentek2. However, they are not cheap which can make it difficult for small businesses and hobbyists to make use of them. An article [6] in an Internet forum describes such a development kit going for $85000.

4.6.2 The API of SCA The SCA specification provides an Application Program Interface (API) which defines struc- tures to simplify the construction of portable SCA applications [13],[8]. These structures are organized much like the OSI model in different layers, with each API describing a layer. This is shown in picture 4.5.

Waveform Network Application

A A

Data and Real-Time A Logical Logical Control Link Layer B Link Layer B B Non-real-Time Control, Setup and Initialization, from applications, other levels, user interface A

MAC B A Layer

I/O Layer B A External Network Connection Physical Layer B

Figure 4.5 Organization of the API layers

Each API is then divided into what is called “Service Groups”, small groups of functions that are relatively closely related. This way, the developer only has to implement the specific functions of the API which is needed for his waveform application.

1http://www.prismtech.com 2http://www.pentek.com 4.6. SCA waveform development 19

For more information on the details of the various API components, see the SCA Devel- oper’s Guide [13] and the SCA API supplement [8]. 20 21

Chapter 5

GNU Radio

This chapter describes the design concepts of GNU Radio.

5.1 Overview

As stated in chapter 2, software radio is about getting the software source code as close to the antenna as possible. Besides that all radio functions such as modulation and filtering takes place in software, reconfiguration and even upgrading your radio over the air to handle a completely new waveform can be done on the fly. GNU Radio [3] is a free toolkit for learning about, building and deploying software radios. It provides a library of signal processing blocks and the glue to tie all together. It is free and thus comes with complete source code, so anyone can make changes or see how the system is built. GNU Radio is designed to be easy to use, while still be powerful enough to handle complex data streams at a high sample rate. Therefore, all signal processing blocks are written in C++, while the procedure of putting them together to create a waveform is done with the scripting language Python1.

5.2 SDR Construction using GNU Radio

The programmer builds a radio waveform by creating a signal-flow-graph, where signal pro- cessing blocks process infinite streams of data flowing from their input ports to their output ports. The signal processing blocks have attributes such as the number of inputs and outputs they have, and what kind of data the streams consist of. The most common types of data are shorts, floats and complex number data. Some building blocks have only output ports or input ports, and these serve as data sources and sinks. Examples of sources include reading from a file or a block which generate sine waves. A sink might be a sound card, an D/A converter or a graphical display.

1http://www.python.org 22 Chapter 5. GNU Radio

5.3 Creating your own building block

There might come a situation when you need a building block that is not included in the GNU Radio packages. Fortunately, there is a comprehensive guide on how to write your own build- ing block, which is found at the GNU Radio web site [4]. There is also an expanded tutorial version of the guide written by Dawei Shen at the Department of Electrical Engineering at the University of Notre Dame [14]. C++ is the language used to create signal processing blocks in GNU Radio. At a high-level point of view, infinite streams of data flow through the ports as mentioned in the previous section. At the C++ level, these streams are ordinary arrays of the particular data type used. When developing a new building block, we need to construct it as a shared library that can be dynamically loaded into Python using the “import” mechanism. More information on how “import” works can be found in the Python tutorial [17]. It’s similar to the “#include” statement in C or C++. To accomplish this, SWIG comes into the picture!

5.3.1 SWIG One of GNU Radio’s strengths is that it uses the powerful scripting language Python to build the waveform at a higher level, but uses C++ functions at a lower level of abstraction. To be able to use the C++ functions at the higher level, a “glue” called SWIG [10] is used. SWIG is an abbreviation for Simplified Wrapper and Interface Generator. SWIG connects programs written i C and/or C++ with various high-level scripting languages such as Python, Perl, PHP or TCL.

5.3.2 Boost One important thing about GNU Radio building blocks, is that they make use of Boost smart pointers. Boost 2 is a collection of C++ libraries, and is required for the installation of GNU Radio. It provides powerful extensions to C++, and GNU Radio uses one of Boost’s useful features: the smart ptr library, so called smart pointers. Smart pointers are objects which stores pointers to dynamically allocated objects. They automatically delete the objects they point to at the appropriate time, since in fact the smart pointers own the object they point to, and therefore are responsible for their destruction. Smart pointers are defined as class templates, so when we need a smart pointer to point to our object, we make a typedef of the template to our particular class. This can be seen in detail in the source code. The point in using smart pointers is that the programmer doesn’t have to be worried about memory leaks and destruction of objects, the Boost library takes care of that. The programmer treats the Boost smart pointer as a regular C++ pointer!

5.3.3 Naming Conventions GNU Radio uses certain naming conventions of files and classes to help the waveform devel- oper keep track of how a component works and what parameters it uses, and also to keep a consistency in how the blocks are constructed. For instance, suffixes are used to indicate the

2http://www.boost.org 5.3. Creating your own building block 23 input and output types of a block. The first character in the suffix shows the input type, while the second indicates the type of the output stream. An example is the block gr_add_ff where the output is the sum of all the inputs. Here _ff says that the input and output streams consist of float types. Several other naming conventions exist, and can be found in the tutorial.

5.3.4 Much more to know Then there are other things needed to be known when creating a new building block, such as the correct directory structure for the files, how to use the GNU autotools for compilation, and how to modify the makefiles. All of these subjects is quite lengthy in detail, and can be read about in the tutorial [14]. We won’t explain them all in this thesis. Some things should be said about the C++ class though.

5.3.5 The C++ Class When constructing a new building block, one creates three files. The .h file where the class declaration goes, the .cc where the actual class implementation is, and a SWIG file, .i, which tells SWIG the gluing guidelines for the building block. It is common practice when creating the class declaration in GNU Radio to make the constructor private. This of course prevents the programmer from creating a new object like this:

square_ff * my_squaring_object = new square_ff();

This is because we always want to make use of the Boost smart pointers! Doing like above would only create a normal C++ pointer. Instead we have a method in the class which returns a Boost smart pointer to the desired object, like this:

\\ This is the header file:

typedef boost::shared_ptr square_ff_sptr; square_ff_sptr make_square_ff();

class square_ff { private:

square_ff(); friend square_ff_sptr make_square_ff(); }

\\ This is the implementation file:

square_ff_sptr make_square_ff() { return square_ff_sptr (new howto_square_ff()); } 24 Chapter 5. GNU Radio

square_ff::square_ff() { // In this example we do nothing }

In this example, we first make a type definition that square_ff_sptr shall be a Boost smart pointer to a square_ff object. Then we declare the method make_square_ff() which returns a Boost smart pointer to a square_ff object. This method is a friend of the square_ff class, and therefore have access to the square_ff constructor! The implemen- tation of make_square_ff() simply returns a typecast Boost smart pointer to a square_ff object, and we use this method whenever we want a new square_ff object. This way we make sure that there will never be any regular C++ pointers to objects in our program!

5.4 A simple example

We end this chapter with a small example of how to use GNU Radio from the end user’s point of view. The following Python example illustrates a simple signal generator, and is taken from the article Exploring GNU Radio [12]. #!/usr/bin/env python

from gnuradio import gr from gnuradio import audio

def build_graph (): sampling_freq = 48000 ampl = 0.1

fg = gr.flow_graph () src0 = gr.sig_source_f (sampling_freq, gr.GR_SIN_WAVE, 350, ampl) src1 = gr.sig_source_f (sampling_freq, gr.GR_SIN_WAVE, 440, ampl) dst = audio.sink (sampling_freq) fg.connect ((src0, 0), (dst, 0)) fg.connect ((src1, 0), (dst, 1))

return fg

if __name__ == ’__main__’: fg = build_graph () fg.start () raw_input (’Press Enter to quit: ’) fg.stop ()

We start by creating a flow graph to hold the blocks and connections between them. The two sine waves are generated by the gr.sig_source_f calls. The f suffix indicates that the source produces floats. One sine wave is at 350 Hz, and the other is at 440 Hz. Together, they sound like the US dial tone. 5.4. A simple example 25

The block audio.sink() is a sink that writes its input to the sound card. It takes one or more streams of floats in the range -1 to +1 as its input. We connect the three blocks together using the connect() method of the flow graph. The connect() method takes two parameters, the source endpoint and the destination endpoint, and creates a connection from the source to the destination. An endpoint has two components: a signal processing block and a port number. The port number specifies which input or output port of the specified block is to be connected. In the most general form, an endpoint is represented as a Python tuple like this: (block, port number). When port number is zero, the block may be used alone. Once the graph is built, we start it. Calling start() forks one or more threads to run the computation described by the graph and returns control immediately to the caller. In this case, we simply wait for any keystroke. 26 27

Chapter 6

Implementation of the MATH Waveform

In this chapter the MATH (MAnsour-THomas) Waveform is described, and in sec- tion 6.2 and section 6.3 our two different implementations of the MATH waveform are discussed.

6.1 Introduction

At the stage in our thesis work when we had acquired knowledge about SCA and CORBA, studied GNU Radio and Python and tried some programming in a CORBA environment to learn even more, we sat down and thought about what kind of waveform we would implement. We figured out that maybe a simple FM or AM waveform would be nice, but after some thinking we thought that wasn’t good enough for the SCA implementation. One necessary thing to have in mind was that we would use the sound cards of ordinary PCs as the analog part of the radio system. Instead of having a real radio transmitter and receiver, we would simply connect two sound cards together and send the data, whatever it might be, over this simulated “radio interface”. After some discussion with our supervisor Daniel, he suggested that we should skip the actual modulation of the signal to begin with, and concentrate on the digital signal pathway in the SCA implementation. The important thing wasn’t the modulation, but to understand the SCA way of designing Software Radio. We would just let the sound cards act as regular D/A and A/D converters. We thought that it would be nice to have some sort of configurable waveform, since this is one of the basic ideas of a software radio. So we decided that we should be able to transmit ordinary sound, but also be able to switch to a text mode where regular text messages could be typed in and transmitted. We named this waveform MATH, which is a sort of abbreviation of our names, Mansour and Thomas. Keep in mind that we hadn’t decided anything about what kind of modulation that could or should be used, this was a decision we postponed. To sum things up, we wanted a waveform that should be configurable to transmit and receive ordinary sound or text messages, and it should have no modulation to start with. Then the actual work began, and we started with the SCA implementation since we realized this would consume most of our time. 28 Chapter 6. Implementation of the MATH Waveform

6.2 SCA implementation

We figured out almost from the beginning that the SCA implementation would take a lot more time than the GNU Radio implementation. First of all, we had to get a working development environment up and running. We knew that we were supposed to develop an SCA waveform, and for that we needed an SCA Core Framework. It turned out that most Core Frameworks were closed source and had to be pur- chased. Our supervisors then found a suitable CF called OSSIE, an open source initiative at Virginia Tech University. They gave us the address to the OSSIE web page, and we were off.

6.2.1 The beginning steps This section is a description on what went on during the first time of our SCA development.

Understanding of CORBA Before we approached SCA we had to have understanding of CORBA. A good start was the CORBA FAQ at OMG’s web site [5]. After we had gotten some comprehension of what CORBA was and how it worked, we installed the TAO ORB [11] which our supervisors had suggested we would use. At the TAO web page we found some CORBA tutorials which we examined thoroughly, and we proceeded by implementing a simple client-server application using the tutorials as help. We then extended this application to include support for the CORBA Naming Service. Now we thought we were ready to take on SCA.

The test example We started by examining the example of an SCA waveform that was shipped with OSSIE. It was a nasty composition of files which didn’t make much sense to us at all. This was even before we had decided what kind of waveform we would develop, we just wanted some hands- on feeling on SCA development. After a lot of reading the source code back and forth, we had somewhat sense of how things worked. Or at least how the OSSIE team thought things should work.

Our first attempt We then tried to do something similar to what the OSSIE team had done, which were more difficult than we expected. Our first attempt at creating a small test-application took us at least a couple of weeks. A lot of time was spent on debugging the OSSIE source code to find out why our application wouldn’t install in the DomainManager. At last we had a small SCA waveform which did absolutely nothing, but at least it was installed within the SCA Domain and everything worked as expected!

SCA Developer’s Guide At this point in time, our supervisor Daniel mentioned a document called “SCA Developer’s Guide” [13]. We had completely missed this highly informative document on the JTRS web 6.2. SCA implementation 29 site! This document turned out to be a huge step forward in understanding SCA and SCA waveform development. The SCA Developer’s Guide is a comprehensive document prepared by the Raytheon Company in 2002. It has an overview of the SCA and all it’s components, on overview of the APIs and domain profile components, and a full chapter with recommendations and pro- cedures the developer can follow during the course of waveform development.

6.2.2 The MATH implementation After we have studied the developer’s guide and discussed matters with our supervisor, we decided to create a model of our application. This model is shown in figure 6.1.

UI

Real Time Non-Real Time

Assembly Controller

Waveform MAC Layer

Waveform Physical Layer

Soundcard "Modem"

Figure 6.1 Model of the MATH waveform

In this model, we see several blocks. The two most important blocks are the Physical and MAC, which represent the two layers “Physical Layer” and “MAC Layer” mentioned in chapter 4, section 4.6.2. Connected to them is the Assembly Controller. It is a required part of an SCA waveform, and the SCA Application component delegates all Resource operations other than getPort() to the Assembly Controller. It also handles the communication with components outside the waveform, and in picture 6.1 we see that the graphical user interface is connected to the Assembly Controller. 30 Chapter 6. Implementation of the MATH Waveform

6.2.3 Functionality

During sending, the signal originates in the MAC layer, and is then sent down to the Physical layer which transmits the signal out on the sound card. The Assembly Controller handles configuration of both the Physical and MAC components. There is a signaling system used in the MAC and Physical layer to handle the data com- munications. This system is described in section 6.2.4. Due to time limitations we never implemented an SCA receiver, therefore only the down- stream real-time transmission line in the picture is used, the one from MAC to Physical. Other- wise, in receiving mode, the Physical component would receive the signal and send it upstream to the MAC component which would handle it in the appropriate way. There is some source code for the receiver though, a sort of skeleton which could be made into a receiver. For that same reason as well as a lot of problems with the sound card, we never finished the text function. As recalled, we wanted to be able to send both audio and text messages. But as we didn’t modulate the signal, the text function wasn’t easy to implement. An easy way would be to modulate 1 bit of the text message as a 16 bit word, since the sound card uses 16 bit words. But experiments with the sound card showed that this was not a good idea. A better way to go would be to implement QPSK or BPSK modulation, but this was something we didn’t look much into due to lack of time. The C++ source code to these components can be found in appendix D.

MAC component

We decided that we would transmit ordinary wave sound files, 16 bit, 2 channels and 44100 kbps. After the application has started, these events occur in the MAC component:

1. A wave file is opened using the Core Framework’s FileSystem. This file is chosen through a file dialog in the user interface. The result is a Core Framework File.

2. A small chunk, which size is configurable, is read from the file. The Core Framework’s File interface reads the data into a CORBA::OctetSequence, which is a sequence of CORBA::Octets that can be unlimited.

3. The file chunk is then repacked and converted into a CORBA::ShortSequence, which is the same as above, but has 16-bit data fields instead of 8-bit. We do this because the sound card is a 16-bit sound card, and therefore it would be nice to have the data in a 16-bit format.

4. Finally, the stream of data packets is sent to the Physical layer.

5. Step 2 to 4 are repeated until the application is stopped.

The wave file can be changed when the application is not running. More exactly, it can be changed at any time through the user interface, but it is not until the application is stopped and started again that the old one is replaced. 6.2. SCA implementation 31

Physical component This is where the actual transmitting of the signal takes place. Embedded in the Physical component is a C++ class for sound functionality since a sound card is to be used for the actual analog transmission. The sound class developed uses ALSA (Advanced Linux Sound Architecture) [1] to communicate with the sound card.

Assembly Controller component The Assembly Controller directs the configure parameters from the user interface to the correct component. It also handles the start() and stop() methods for the whole Application. The Assembly Controller is a component required by the SCA specification. It doesn’t have to be a separate component, another SCA component can act as the Assembly Controller as well. We decided however to put it in a separate block.

The Graphical User Interface In figure 6.2, a picture of the user interface is shown. When starting our application, this is what the user see. There are buttons for installing and uninstalling an SCA Application into the Domain Manager. Any SAD file can be chosen to be installed. When installed, the start and stop buttons can be used to start and stop the Application. There are also functions to choose which wave file to be played, if the application should be in audio or text mode and a checkbox to inhibit or shut down the physical transmission.

Figure 6.2 The SCA implementation of MATH

6.2.4 Signaling system On a lower layer of description, the data that is moved from the MAC component to the Physical is stored in buffers. To prevent these buffer to be congested, a signaling system is used. This system is taken from the SCA API building blocks, and is called SignalsBB. SignalsBB has three methods, signalHighwatermark, signalLowwatermark and signalEmpty. When the receiving buffer in the Physical component is starting to get full, Physical sends a 32 Chapter 6. Implementation of the MATH Waveform signalHighwatermark to MAC to indicate what is happening. MAC then stops the data stream to let the Physical process the data in the buffer. When the receiving buffer in the Physical component is starting to be depleted, Physical sends a signalLowwatermark in order for MAC to start sending more data. The third signal, signalEmpty, is used to check the status of a buffer. This method return “true” if the buffer is empty.

6.3 GNU Radio implementation

In GNU Radio, the scripting programming language Python is used to connect blocks together, and to start and stop the application. The basic idea is that the waveform developer designs a signal-flow-graph in Python using the GNU Radio building blocks. To start the waveform, the Python application calls the start() method on the signal- flow-graph. Then there is a runtime system which does all the work of instantiating the correct classes and libraries, creating threads for execution, and makes sure there is a correct data flow between the different blocks. The runtime system is provided in the GNU Radio Core package, and one doesn’t have to worry about it at all as a waveform developer. When we got to the GNU Radio implementation time was running short, so we decided that we should only try to model and implement the receiving part of MATH in GNU Radio. The SCA implementation was as recalled modeled to be both transmitter and receiver, though only the transmitting part was actually implemented. Since GNU Radio is totally different from SCA in the meaning that a lot of building blocks already exist, we started by examining what blocks already existed, and what we might need for our waveform. We expected that at least one GNU Radio building block had to be implemented, some kind of MATH decoding block.

6.3.1 First attempt

When we first attacked the problem, we thought that a structure as shown in figure 6.3 would be a good start for the MATH waveform. The figure shows the signal-flow-graph which would later be created in Python. The MATH demux building block would take care of the separation of audio and text, and send them to the correct place. The audio sink would play sound, after it had been low pass filtered. The text output block would print the text messages. The FIR filter block comes in the GNU Radio core package for both floats and complex input and output streams, and the audio source and sink are also available in a separate pack- age. So we didn’t have to implement these. It turned out that we couldn’t find a block that simply printed text on a terminal, so besides the MATH demux block this block had to be implemented as well. But after studying the build-your-own-block-tutorial and doing some work on the MATH demux block, we encountered a problem. The current version of GNU Radio only supports the same data rate for all output streams. We couldn’t shut off the pathway to the text box when audio is coming in, or have the audio sink not receiving any data if we are in text mode. This was a major setback, so we had to find another solution. 6.3. GNU Radio implementation 33

Figure 6.3 First model for GNU Radio implementation of MATH

6.3.2 Two signal-flow-graphs One way of solving the problem would be to have two signal flow graphs. One to use in text mode, and one for the audio mode. These two graphs would then be started and stopped in Python, accordingly to which mode we wanted to be in. Figure 6.4 shows a model of this.

math_text_graph:

audio Text Terminal source decoding text output

math_audio_graph:

audio FIR filter audio sink source

Figure 6.4 Second model for GNU Radio implementation of MATH

The text decoding block and the text output block could perhaps be combined to one block as well, as they both needed to be implemented.

6.3.3 The actual implementation Since stated earlier in this thesis, we never got to implement the text part of the MATH waveform. Therefore, the text decoding block doesn’t contain much. We gave it the name math_console_writer_f, where the _f states that the block takes floats as input. The idea is to decode the input stream, and print the message on stdout or some other output console. Though our block doesn’t perform any signal processing, it integrates and works in the GNU Radio environment nevertheless! The block was implemented as sort of a “black hole”, is just takes data on the input and does nothing with it. 34 Chapter 6. Implementation of the MATH Waveform

6.3.3.1 The C++ code It is not that hard to implement your own building block, we just followed the example in the tutorial [14], which is really good and comprehensive. It mostly involves following a recipe where you besides writing the class for your block, replace some rows in the GNU autotools configuration files and the SWIG configuration file. These files can be downloaded together with the tutorial at the GNU Radio web site. The documentation on these GNU autotools files is very sparse in the tutorial, and it is recommended that anyone who wants to develop own signal processing blocks learns how to use, create and modify them. We ran into some problems when compiling our block, and this was related to the fact we didn’t know how these files worked. But after some troubleshooting things worked as expected. We can mention that there is some SWIG magic behind the scenes when the block com- piles. This way, we can access the math_console_writer_f block using the regular Python notation math.console_writer_f(). The C++ source code can be found in appendix C.

6.3.3.2 The Python code We started off in an uncommon way by implementing the Graphical User Interface (GUI) first. We wanted to have a similar look as the SCA implementation, so wxPython 1 was the way to go. More information about this way of writing portable user interfaces can be found in appendix A. The application consists of two signal-flow-graphs as shown in figure 6.4, which we then could alternate between using two common radio buttons in the GUI. The GUI also provides a way of starting and stopping the waveform. The signal-flow-graphs are quite simple. The first which implements the audio part consist of an audio source, where the signal is received from the sound card. It is followed by a low- pass FIR filter to filter out any high-frequency noise components in the signal. Finally, the sig- nal is connected to an audio sink. The other signal-flow-graph which would implement the text part is even simpler. It starts with an audio source, followed by our math_console_writer block. The Python code can be found in appendix C.

1http://www.wxpython.org 35

Chapter 7

Conclusions

In this chapter we draw conclusions of our work. Pros and cons of the two different ways of developing Software Radio are presented, and we end the chapter with a comparison of the two methods.

7.1 Developing waveforms using SCA

7.1.1 Benefits and advantages First of all, the SCA is a well defined, open standard. There are no license costs or other means which may prevent developers of using it. This make it a good base for interoperability and information exchange. Second, the SCA is a strictly defined set of guidelines. If these guidelines are followed, it is very easy to make portable waveforms. Parts of one waveform on one platform can easily be re-used in another waveform on another platform.

Benefits using CORBA IDL structures The CORBA IDL is a very strictly defined language, which makes sure that the resulting code behaves exactly the same way regardless of what language it is compiled into, or on what platform. This is good for a developer using CORBA IDL, since he can be 100 % sure that his application will be platform independent, and work in any environment. CORBA itself is developed with high performance and scalability in mind, which makes it a good choice as the SCA middleware. Since the interfaces that the SCA CF consists of are defined in CORBA IDL they can be used on any platform or CPU, and waveforms can be developed using any programming language as long as there is an IDL compiler for it. This way, the SCA makes it very easy to develop portable waveforms. The possibility of easily taking building blocks from one waveform and using them in another can help cut the development time and costs significantly. Also, different parts of a waveform application can run on different machines or devices using different operating systems and CPUs. Using CORBA as middleware does not only ease communications within the waveform and makes sure strict interfaces are defined, it also separates the underlying operating system from the application which aids portability. 36 Chapter 7. Conclusions

Easy generating new interfaces Once the waveform developer has come across the initial quite high step of gaining the re- quired knowledge regarding SCA, it it fairly easy to create new interfaces and waveform mod- els and integrate these into a waveform application. For instance, one can model the interfaces in UML and then generate the appropriate IDL from the UML.

7.1.2 Disadvantages of SCA We have found several difficulties with the SCA, and they are presented below.

High learning threshold In the beginning of our work we almost immediately came across what we think is the biggest disadvantage of SCA, it takes a lot of time understanding what it is all about! Our first en- counter with SCA was the picture on page 6, which didn’t make sense at all, and a printout of the huge SCA specification[9]. It took us weeks just to get an overview of how the structures work, and even now when we are finished it still can be difficult to understand and remember how some things work and are used. The SCA is a very complex specification, with a lot of different files and events that much occur in order to have a working application. This in combination with sparse detailed doc- umentation how to develop waveform applications creates a rather high threshold of under- standing to overcome, before being able to begin the work on the actual waveform.

Disadvantages regarding CORBA Another major issue we had lots of problems with was the CORBA environment. CORBA itself is not difficult to understand and use. It was when we had several programs that were to interact with each other the problems occurred. Our Physical and MAC resources were both CORBA servers and clients at the same time, and the problem was really how to use the CORBA event loop and the ORB itself in a good fashion without losing performance. We spent many days searching for good ways of doing this, and tried different solutions. We once even rewrote our whole CORBA initialization code from scratch in despair. Here is the scenario: The server part of each resource has to wait for incoming CORBA re- quests, which is done by a call to the ORB::run() method or to the ORB::perform_work() method. The first is a call which never returns unless the ORB is shut down or destroyed. But in our case it didn’t even return if the ORB was destroyed, for reasons we were unable to find. The latter method performs one unit of work, and then returns. There is also a method called ORB::work_pending() which checks if there is any CORBA work to be done for a particular servant, and this is used in conjunction with ORB::perform_work(). We weren’t able to use the ORB::run() call since we couldn’t shut down our processes upon exiting the application, so our application uses ORB::perform_work(). Our prob- lems showed up as time delays and hang-ups when calling ORB::perform_work() from several processes. At first there was just a major hang-up in all the processes. None of the components worked, they were all waiting for their ORB calls to return, as they depended on each other 7.2. Developing waveforms using GNU Radio 37 to finish. This was finally solved by studying our particular ORB in detail. We managed to configure the ORB in such a way that it created a new processing thread for every incoming call, making it possible to have several calls at once to the ORB. The problem and solution probably took us a week to find and solve. Then another problem occurred. When the processes called ORB::perform_work() in their main loop, there were sometimes long time delays until the call returned. This in turn produced an output audio signal with “gaps” in it, thus making it far from a real-time application. This was unacceptable of course, and much time were spent finding a solution. Finally, we tried to remove the ORB::perform_work() call from one of our processes. We didn’t expect that this component would work at all by doing this, but to our surprise the whole application worked super smooth! We never found out exactly what happened or why the components worked after this, it seemed to us like some CORBA magic. This became a very annoying solution to our problem, since we didn’t understand it. But then again, time was running short, and we had to move on.

7.1.3 Conclusions about the SCA In our work we have discovered that a lot of our time was spent examining and debugging the SCA CF, and even more time was spent getting a well working multi-component CORBA application. This steals the focus of the actual waveform application, the part that really should matter! Also, having to write all the XML and get that syntactically right, generating UUID numbers etc, is something that isn’t essential to a waveform developer and he shouldn’t have to be concerned about it. In general, XML is good for computers to read, not people. All of this is however good for the understanding how the SCA works, and we would recommend for an SCA waveform developer to at least have tried it once. It would be very appreciated when developing SCA waveform applications to have some sort of development tool which takes care of not only handling of the CF, but also the CORBA integration and generation of the XML needed for the application. All setup of the components and their communications channels, the XML generation and well as all the setup regarding the DomainManager etc could be auto generated by such a development tool-kit. It should of course be highly configurable, detailed description possibilities regarding in- ternal communications channels in an application should for example be provided. Further- more, the waveform developer should be able to perform most or all of the work “by hand” if he wanted.

7.2 Developing waveforms using GNU Radio

7.2.1 Advantages of GNU Radio GNU Radio has several advantages, in this section we present the benefits of using GNU Radio that we have found.

• It is very easy to get started! This is probably one of the greatest things about GNU Radio. After installation and reading the GNU Radio documentation [2] for new users, it doesn’t take more than a few minutes to have a small waveform application going. 38 Chapter 7. Conclusions

• GNU Radio is free open-source software. This makes it possible for anyone to expand the GNU Radio tool-kit with new functions and signal processing blocks.

• Good run-time system. The waveform developer doesn’t have to be concerned about data rates, memory allocation for communication buffers and so forth. One specifies what kind of data a block uses, and what data rate the inputs and outputs shall use. Then the run-time system does all the hard underlying work.

• Many tools and components are provided. Included in GNU Radio’s core package is a vast number of ready-to-use components such as filters, signal sources and modulators for the waveform developer to use. It also comes with a spectrum analyzer and an oscilloscope.

• There exists cheap development hardware. The Universal Software Radio Peripheral (USRP) is piece of hardware developed by the GNU Radio team. It consists of a moth- erboard equipped with an FPGA for some basic DSP functions, and can hold up to 4 daughterboards used for transmitting and receiving. The USRP is open source as well, and if a developer doesn’t want to build one of his own it can be purchased for about $100–$150.

7.2.2 Disadvantages and drawbacks As with all software implementations, GNU Radio has some drawbacks as well.

Lack of documentation

The underlying run-time system of GNU Radio is difficult to understand and get a grip of. There are some SWIG “magic” functions and other parts that aren’t easy to apprehend. Most of this is due to the shortage of documentation, especially when it comes to development of new building blocks. There is a tutorial on the GNU Radio web site, and during our thesis work a more compre- hensive version was released. But there is very little, one might even say no documentation on how the underlying run-time system works. There is of course the freely distributed source code to read, but that is not an easy task for most people.

Environment limitations

When using GNU Radio, Python is the language which the user writes his application in. If the user wants to develop a new building block, this is done in C++. In other words, the development and usage languages are limited to these two. One can imagine that a developer could write a building block in some other language, but it would probably be difficult to insert into the GNU Radio run-time system. The operating system is also a limiting factor. GNU Radio is primarily developed for the Linux platform. There are reports that it compiles on certain variants of Solaris and some people are trying to get it to work on the Windows platform. However, if one wants to be sure to have a working GNU Radio system, Linux is the operating system to use. 7.3. Comparison of the two methods 39

7.3 Comparison of the two methods

A comparison between the SCA and GNU Radio is not easy to make since they are so different. One of the most important differences is that SCA is a kind of specification used to help developers produce interoperable, portable radio waveforms. The SCA is a set of guidelines, and it is up to the software developer to choose how the application will look like, as long as he follows the SCA guidelines. This in comparison to GNU Radio, which is an implementation of a software radio, with a underlying run-time system and a lot of building blocks. It is basically a ready-to-use toolbox of various waveform components! It is more like a box of LEGO, the developer only has to put together already finished pieces to produce a software radio.

Difficulty and understanding issues GNU Radio could be considered a lot simpler than the SCA. It takes a short amount of time to create a working SDR, compared to creating one the SCA way. If one wants an SDR right away, preferably yesterday, and since GNU Radio is an imple- mentation as opposed of the SCA, GNU Radio is a good alternative. On the other hand, if one wants an SDR that is compatible with other JTRS waveforms and portable among several different platforms, SCA is a better way to go.

Development costs GNU Radio is probably cheaper than the SCA. There exist developer kits for the SCA, but they have a rather high price compared to the free GNU Radio. For the amateur or small company, many of these kits aren’t even worth considering. One could of course use an open source Core Framework as we did in this thesis, which cuts the costs. But this way, the SCA takes a lot more time to apprehend, which produces higher costs as well in terms of developers salaries. 40 41

References

[1] Advanced linux sound architecture. .

[2] Exploring GNU Radio, . .

[3] The GNU Radio web site, . .

[4] How to write your own GNU Radio building block. .

[5] OMG CORBA web site. .

[6] Pentek offering an SCA development kit. .

[7] SCA Naming Service Specification version 1.3. .

[8] SCA Specifications and Requirements v3.0. .

[9] Software Communications Architecture Specification v3.0. .

[10] SWIG - Simplified Wrapper and Interface Generator. .

[11] The TAO (Ace Orb) web site. .

[12] Eric Blossom. GNU radio: Tools for Exploring the Radio Frequency Spectrum. . 42 References

[13] Raytheon Company. Joint Tactical Radio System(JTRS) SCA Developer’s Guide. .

[14] 2005 Dawie Shen May 19. GNU Radio Installation Guide - Step by Step. . [15] Ivar Jacobson Grady Booch, James Rumbaugh. The Unified Modeling Language User Guide. Addison-Wesley, 1999. ISBN 0-201-57168-4.

[16] Erik T. Ray. Learning XML, Second Edition. O’Reilly, 2003. ISBN 0-596-00420-6.

[17] Guido van Rossum and editor Fred L. Drake, Jr. Python Tutorial Release 2.4.1. . 43

Index

A ADC (Analog-to-Digital Converter), 4 AggregateDevice, 12–14 ALSA (Advanced Linux Sound Architecture), 31 Application, 11, 14 Application Program Interface (API), 18 ApplicationFactory, 12–14 Assembly Controller, 14 audio.sink(), 25 B Boost smart pointers, 22, 24 C C++, 21, 34 CF (Core Framework), 1, 5, 9, 11, 12, 28 configure(), 13, 16 connectPort(), 13 CORBA (Common Object Request Broker Architecture), 1, 6, 7, 17, 28 CORBA middleware, 6, 11, 18 D DCD (Device Configuration Descriptor), 17 Device, 12–14, 17 DeviceManager, 12–14 disconnectPort(), 13 DoD (Department of Defense), 5 Domain Profile, 11, 12, 15 DomainManager, 12–14, 17 DTD (Document Type Definition), 15 E ExecutableDevice, 12–14 F FileManager, 15 FileSystem, 15 FIR (Finite Impulse Response) filter, 32 44 Index

G getPort(), 13 GIOP (General Inter-ORB Protocol), 7, 8 GNU Radio, 1, 4, 21, 24 GPS receiver, 4 GSM telephone, 3 GUI (Graphical User Interface), 34 H HDTV (High-Definition TeleVision), 5 HTML (HyperText Markup Language), 15 I IDL (Interface Definition Language, 5 IDL (Interface Definition Language), 7, 11, 17 IIOP (Internet Inter-ORB Protocol), 7, 8 initialize(), 13 IOR (Interoperable Object Reference), 7 J JTRS (Joint Tactical Radio System), 5 L LifeCycle, 12 Linux Journal, 4 LoadableDevice, 12–14 M MATH (MAnsour-THomas waveform, 27 MATH (MAnsour-THomas waveform), 27 N Naming Service, 9, 28 O OE (Operating Environment), 5 OMG (Object Management Group), 7 ORB (Object Request Broker), 7, 9 OSSIE (Open Source SCA Implementation::Embedded), 28 P Perl, 22 PHP (Hypertext Preprocessor), 22 POA (Portable Object Adapter), 9 Port, 12 PortSupplier, 12 POSIX (Portable Operating System Interface Standard), 6 PRF (Properties Descriptor File), 16 PropertySet, 12 Index 45

provides port, 17 Python, 21, 24, 25, 34 Python tutorial, 22 Q QoS (Quality of Service), 9 query(), 13, 16 releaseObject(), 13 Resource, 11, 13, 16, 17 ResourceFactory, 12 RF front end, 4 runTest(), 13, 16 S SAD (Software Assembly Descriptor), 17 SCA (Software Communications Architecture), 1, 5, 11 SCD (Software Component Descriptor), 16 SDR (Software Defined Radio), 1, 3, 4, 21 SGML (Standard Generalized Markup Language), 15 signal-flow-graph, 21, 32, 33 Software Profile, 12 SPD (Software Package Descriptor), 16 start(), 13 stop(), 13 SWIG (Simplified Wrapper and Interface Generator), 22, 23, 34 T TAO (The Ace Orb), 9 TCL (Tool Command Language), 22 TestableObject, 12 U UML (Unified Modeling Language), 13 Universal Software Radio Peripheral (USRP), 38 uses port, 17 W Waveform, 3, 27 waveform, 11 WCDMA (Wideband Code-Division Multiple-Access), 3 wxPython, 34 X XML (eXtensible Markup Language), 11, 15 46 47

Appendix A

Platform-related issues

This appendix deals with the problems and issues with compilers, libraries and other platform related concerns we’ve had during our thesis work.

Introduction

During our work there has been several software related problems, some which have been easily resolved, and others that were a harder nut to crack. Much time and effort has been spent to solve these problems, and this appendix could be of help to others who are trying to develop Software Defined Radio using a Linux platform. As the general platform, we used the Linux distribution Fedora Core 3 (FC3) as recom- mended. This platform uses the RPM packaging system, which none of us had used much before. The choice of FC3 turned out to be not such a good idea for our development work.

GNU Radio issues

GNU Radio was very easy to install, just grab the packages from the GNU Radio download site1, unpack them, compile and install using the standard GNU autotools. There was one major problem during the installation of GNU Radio, the SWIG library needed for GNU Radio to compile had to be of version 1.3.24 or later. The version coming with FC3 was version 1.3.21. After a lot of hassle with searching for RPM packages of the right version we found a source RPM for SWIG 1.3.24, and managed to compile that into an RPM package and install into our system. A small problem occurred with the ALSA support for GNU Radio. ALSA is the sound application interface used in Linux operating systems, and the ALSA modules for GNU Radio is fairly new and in a high beta stage. As it says in the README file, “This is currently a work-in-progress and is not ready for use”. In order to get a 48000 samples/second sampling frequency with GNU Radio, we had to use the older way to implement sound in Linux, the OSS interface. The OSS module for GNU Radio turned out to work fine, but in order for it to work at all, OSS support has to be installed in the Linux Kernel.

1http://comsec.com/wiki?GnuRadio2.X 48 Appendix A. Platform-related issues

SCA issues

During the time we spent trying to understand and develop an SCA waveform, a lot of platform-related problems occurred.

TAO and gcc

At the time, OSSIE was using TAO (The ACE ORB) for its CORBA-related operations, so we had to install TAO to begin with. First of all, compiling ACE and TAO takes a lot of time, and we had to do it a couple of times to get things right. Approximately two days were all about compiling TAO. Then it turned out that TAO has a major flaw! The TAO IDL compiler produces C++ source code which cannot be compiled with gcc 3.4. Guess which version of gcc is shipped with Fedora Core 3? We didn’t know at first what the problem was, we just couldn’t compile the source code. Then we read at the OSSIE web page that they had had issues with gcc 3.4 as well, and recommended gcc 3.3 instead. Getting gcc 3.3 installed in FC3 was easier than we first thought. After a couple of days of struggling with RPM packages and dependencies, we found a package called compat-gcc which included the next latest compiler. This was in our case gcc 3.3! But this was really an ugly workaround. In the next release of Fedora, gcc 4.0 is standard and gcc 3.4 is the compat-gcc. This means that Fedora Core 4 won’t work with TAO. Here we started to regret that we used Fedora instead of the Debian distribution. In Debian, gcc packages exist for most versions and can easily be installed without any fuss at the same time. By the way, GNU Radio has compile issues with gcc 3.3, and gcc 3.4 is recommended . . .

ALSA

The Linux sound API is named ALSA, and since we were supposed to use sound cards to transmit and receive the data, we had to learn how to program the ALSA API as well. It turned out that the ALSA version shipped with FC3 was not up-to-date with the ALSA tutorials we wanted to use, so we had to find and install the latest version of ALSA instead.

Hardware

The computers we used during the thesis came equipped with built-in sound cards. These didn’t quite work as expected, we weren’t able to record any sound at all with them! Not with our own developed software, nor with any other program we had at hand. The only way we could detect that an audio signal actually was received on the other end was that it went straight through from the input connector to some built-in speaker. Very strange behavior indeed. Luckily the department approved of our request of having new PCI sound cards purchased, and after we had received these everything worked as expected. But approximately a week of our time was lost due to this sound card debugging. 49 wxGTK A test example of an SCA waveform was bundled with OSSIE, and for the graphical stuff it used wxWidgets 2. The version of wxWidgets we wanted was wxGTK 2.4.2, which compiled and installed nicely. But the test application wouldn’t work! We couldn’t first figure out what was wrong, everything seemed to be in order. After a lot of debugging and googling we finally had the solution. It turned out that wxGTK 2.4.2 had an issue with GTK 2.4.x, which is the graphical tool-kit wxGTK is com- piled against. There had been some internal changes in later versions of GTK 2.4 and wxGTK 2.4.2 hadn’t accounted for these changes. Of course the version shipped with FC3 had these internal changes. Luckily we found and applied a wxGTK 2.4.2 patch to fix this problem and then things worked as expected.

OSSIE Finally, the Core Framework that we used, OSSIE, turned out to be in an early beta stage, and was full of bugs. A lot of time has been spent chasing and correcting bugs in OSSIE. This was great for a deeper insight in the SCA structures, but it was something we hadn’t expected we would have to do.

2http://www.wxwindows.org 50 51

Appendix B

Installation Guide

This appendix should have all the information needed to install and try our implemen- tation of the MATH waveform. It is assumed that the reader has some knowledge of Unix’s shell environments, and of Linux in general.

GNU Radio implementation

First of all Python needs to be installed, but as Python comes installed as default with most Linux distributions, we assume that this already is done. Go to the GNU Radio download page1 and the grab the latest GNU Radio core packages, the audio packages alsa and oss, and the wx package. Follow the installation instructions provided in these packages to compile and install GNU Radio. Then simply put the MATH Python source code somewhere, and run the Python applica- tion! Simple as that.

SCA implementation

In order for the SCA transmitter to compile and run, some additional software has to be in- stalled. Also, don’t forget to set the correct shell variables as stated in the last section of this appendix. • OSSIE This is the Core Framework used in our project. The source code can be found at . We have been using version C which can be found at the download page, but that version will not work with our application since we had to fix bugs in it for things to work. One way to find a better version of OSSIE is to go to the OSSIE bulletin board, there is a link at the web site. More recent snapshots of OSSIE can be found there. The best way of running our application and to make sure it works, is to use our bugfixed version of OSSIE, which can be found bundled together with the complete MATH source code at . This is the same source code as found in appendix D and C.

1http://comsec.com/wiki?GnuRadio2.X 52 Appendix B. Installation Guide

• TAO ORB TAO is the ORB used in this project. It’s probably the one thing which takes the most time to compile. The source can be found at the TAO web page [11]. Grab version ACE- 5.4+TAO-1.4 which is the same as we have used and follow the installation instructions.

• Xerces-C++ Xerces-C++ is the XML parser needed by the OSSIE CF. Download and install it before trying to compile OSSIE. Xerces-C++ can be found at , we have used version 2.6.0 in this project.

When all additional software is installed and the correct shell variables have been set up as stated last in this appendix, the SCA MATH source code should compile and run without any problems. The correct way of compiling is to go to the main source directory, type “make idl” to compile the IDL source, and then “make” to compile all of the C++ source code. wxWidgets

Both applications uses the portable graphical user interface wxWidgets which can be found at . The GNU Radio application uses the Python version of wxWidgets, this is found at . Download the latest version and install, and the applications should work fine.

Shell variables

In order for things to work correctly, several shell variables have to be set. Some of them relates to TAO ORB, others to OSSIE and some to GNU Radio. These variables are used during compilation and running of the applications. Below are the relevant lines extracted from the initialization file ∼/.bashrc:

export ACE_ROOT=/usr/src/ACE_wrappers export TAO_ROOT=$ACE_ROOT/TAO export XERCESCROOT=/usr/local/xerces-c-src_2_6_0

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig export PATH=$PATH:$XERCESROOT/bin export PATH=$PATH:$ACE_ROOT/bin export PYTHONPATH=/usr/local/lib/python2.3/site-packages/

export OSSIEROOT=$HOME/src/ossie export OSSIEIDL=$HOME/src/ossie/ossieidl export OSSIEPARSER=$HOME/src/ossie/ossieparser export OSSIECF=$HOME/src/ossie/ossiecf

export LD_LIBRARY_PATH=/usr/local/lib:$XERCESCROOT/lib:$ACE_ROOT/lib:\ $ACE_ROOT/ace:$OSSIECF/lib:$OSSIEPARSER/lib:$OSSIEIDL/lib

Add these lines to your ∼/.bashrc file, or equivalent file if you are using another shell. Of course you have to modify them to suit your installation of TAO, Python etc. 53

Appendix C

MATH GNU Radio Python application

This appendix includes the Python and C++ source code to the MATH waveform.

Python source code This is the main Python application, including the GUI.

#!/usr/bin/python import os import wx from gnuradio import gr from gnuradio import audio_oss from gnuradio import math

ID_ABOUT=1 ID_EXIT=2 ID_START=3 ID_STOP=4 ID_MODESEL=5

# GNU Radio signal-flow-graph functions

# Sample rate throughout the whole graph sampling_freq = 48000

# Input and output signal_in = audio_oss.source(sampling_freq) signal_out = audio_oss.sink(sampling_freq) def build_audio_graph (): # volume gain for the FIR filter gain = 1 # cut-off frequency cutfreq = 20000 # width of transition band transwidth = 1000

# Compute FIR filter taps taps = gr.firdes.low_pass (gain, sampling_freq, cutfreq, transwidth, gr.firdes.WIN_HAMMING) # Using Hamming window

# The FIR filter 54 Appendix C. MATH GNU Radio Python application

mathFIR_left = gr.fir_filter_fff(1, taps) mathFIR_right = gr.fir_filter_fff(1, taps)

# Create a signal-flow-graph fg = gr.flow_graph()

# Connect the building blocks fg.connect ((signal_in, 0), mathFIR_left) fg.connect ((signal_in, 1), mathFIR_right) fg.connect (mathFIR_left, (signal_out, 0)) fg.connect (mathFIR_right, (signal_out, 1))

return fg def build_text_graph ():

# our MATH text decoding block math_block = math.console_writer_f()

# Create a signal-flow-graph fg = gr.flow_graph()

# connect the graph fg.connect((signal_in,0), math_block)

return fg

# Create a main MATH frame class which inherits from wxFrame # This is where all the GUI thingies are. class MATHframe(wx.Frame):

# Override the __init__ method inherited from wxFrame def __init__(self,parent,id,title): wx.Frame.__init__(self, parent, wx.ID_ANY, title, size=(350,250), pos=(50,50), style=wx.DEFAULT_FRAME_STYLE| wx.NO_FULL_REPAINT_ON_RESIZE)

# Create a status bar self.CreateStatusBar()

# A small menu. mathmenu= wx.Menu() mathmenu.Append(ID_ABOUT, "&About"," Information about this program") mathmenu.AppendSeparator() mathmenu.Append(ID_EXIT,"E&xit"," Terminate the program")

# Creating the menubar. menuBar = wx.MenuBar() menuBar.Append(mathmenu,"Menu") # Adding the "mathmenu" to the MenuBar self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.

# Events when menuitems are chosen or buttons clicked. wx.EVT_MENU(self, ID_ABOUT, self.OnAbout) wx.EVT_MENU(self, ID_EXIT, self.OnExit) wx.EVT_BUTTON(self, ID_EXIT, self.OnExit) wx.EVT_BUTTON(self, ID_START, self.OnStart) wx.EVT_BUTTON(self, ID_STOP, self.OnStop) wx.EVT_RADIOBOX(self, ID_MODESEL, self.OnRadioButton)

# Create sizers to hold the buttons self.mainsizer = wx.BoxSizer(wx.VERTICAL) self.buttonsizer1 = wx.BoxSizer(wx.HORIZONTAL) self.buttonsizer2 = wx.BoxSizer(wx.HORIZONTAL)

self.buttonsizer1.Add(wx.Button(self, ID_START, "Start", wx.Point(-1,-1), wx.Size(-1,-1)), 0, wx.ALL, 10) self.buttonsizer1.Add(wx.Button(self, ID_STOP, "Stop", wx.Point(-1,-1), wx.Size(-1,-1)), 55

0, wx.ALL, 10)

self.modelist = [’Audio’, ’Text’]

self.buttonsizer1.Add(wx.RadioBox(self, ID_MODESEL, ’Mode Selection’, choices = self.modelist, majorDimension = 1, style = wx.RA_SPECIFY_COLS), 0, wx.ALL, 10)

self.buttonsizer2.Add(wx.Button(self, ID_EXIT, "Quit", wx.Point(-1,-1), wx.Size(-1,-1)), 0, wx.ALL, 10)

self.mainsizer.Add(self.buttonsizer1, 0, wx.ALIGN_LEFT) self.mainsizer.Add(self.buttonsizer2, 0, wx.ALIGN_LEFT)

self.SetSizer(self.mainsizer) self.SetAutoLayout(1) self.mainsizer.Fit(self)

self.Show(True)

# set up waveform self.audio_fg = build_audio_graph() self.text_fg = build_text_graph() self.is_running = 0 self.main_fg = self.audio_fg def OnAbout(self,event): # Create a message dialog box d=wx.MessageDialog(self, "This is the GNU Radio implementation of the MATH waveform", "About MATH", wx.OK) d.ShowModal() d.Destroy() # finally destroy it when finished. def OnExit(self,event): self.Close(True) # Close the frame. def OnStart(self, event): if self.is_running == 1: self.SetStatusText("Already running!")

else: self.is_running = 1 # Start waveform self.main_fg.start() self.SetStatusText("Starting waveform") def OnStop(self, event): if self.is_running == 1: # Stop waveform self.main_fg.stop() self.SetStatusText("Stopping waveform") self.is_running = 0 else: self.SetStatusText("Can’t stop, waveform is not running.") def OnRadioButton(self, event):

if self.is_running == 1: self.SetStatusText("Please stop application before changing mode.") elif event.GetInt() == 0: self.SetStatusText("Audio mode selected.") self.main_fg = self.audio_fg else: self.SetStatusText("Text mode selected") self.main_fg = self.text_fg 56 Appendix C. MATH GNU Radio Python application

# The MATH class which inherits from wx.App class MATH(wx.App): def OnInit(self):

# The main frame frame = MATHframe(None, -1, "GNU Radio MATH waveform")

self.SetTopWindow(frame) frame.Show(True) return True

# The main application init function if __name__ == "__main__": application = MATH(0) application.MainLoop()

C++ source code Here is the declaration and implementation of our math console writer f signal processing block.

Declaration

#ifndef INCLUDED_MATH_CONSOLE_WRITER_F_H #define INCLUDED_MATH_CONSOLE_WRITER_F_H

#include class math_console_writer_f; typedef boost::shared_ptr math_console_writer_f_sptr;

// This is the public interface to the class. math_console_writer_f_sptr math_make_console_writer_f(); class math_console_writer_f : public gr_block { private: // math_make_console_writer_f has to be a friend of the class // to be able to call the private constructor. friend math_console_writer_f_sptr math_make_console_writer_f();

math_console_writer_f(); // Private contructor public: ˜math_console_writer_f(); // Public destructor

// general_work is where everything really happens. // It’s a virtual method from gr_block which is overridden here.

int general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items);

};

#endif /* INCLUDED_MATH_CONSOLE_WRITER_F_H */

Implementation

#ifdef HAVE_CONFIG_H #include "config.h" 57

#endif

#include #include #include

// This is effectively the constructor of the class math_console_writer_f_sptr math_make_console_writer_f() { // Make a cast to a Boost smart pointer return math_console_writer_f_sptr (new math_console_writer_f()); }

// Specify constraints on the number of inputs and outputs. static const int MIN_IN = 1; // mininum number of input streams static const int MAX_IN = 1; // maximum number of input streams static const int MIN_OUT = 0; // minimum number of output streams static const int MAX_OUT = 0; // maximum number of output streams

// The private constructor math_console_writer_f::math_console_writer_f() : gr_block("console_writer_f", gr_make_io_signature(MIN_IN, MAX_IN, sizeof(float)), gr_make_io_signature(MIN_OUT, MAX_OUT, sizeof(float))) { // We don’t need anything else in our constructor }

// Destructor math_console_writer_f::˜math_console_writer_f() { }

// general_work, an overridden virtual method // where all the work is done int math_console_writer_f::general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { const float * math_in = (const float *) input_items[0];

// Since the text mode isn’t implemented, we are doing nothing here. // Decoding the input stream "math_in" and printing the message to stdout or some // other output stream would be enough.

std::cout << "This is the MATH GNU Radio application running in text mode" << std::endl;

// Though, we still tell runtime system how many output items we produced. // This block can be seen as a "black hole" right now.

return noutput_items; }

The SWIG file math.i This is how the SWIG configuration file used for our block looks like.

/* -*- c++ -*- */

%feature("autodoc", "1"); // generate python docstrings

%include "exception.i" %import "gnuradio.i" // the common stuff 58 Appendix C. MATH GNU Radio Python application

%{ #include "gnuradio_swig_bug_workaround.h" // mandatory bug fix #include "math_console_writer_f.h" // Our MATH include file #include %}

// ------

/* * GR_SWIG_BLOCK_MAGIC does some behind-the-scenes magic so we can * access math_console_writer_f from python as math.console_writer_f * * First arg ’math’ is the package prefix. * Second arg is the name of the class minus the prefix. */ GR_SWIG_BLOCK_MAGIC(math,console_writer_f); math_console_writer_f_sptr math_make_console_writer_f();

/* Class declaration */ class math_console_writer_f : public gr_block { private: math_console_writer_f(); // the private constructor }; 59

Appendix D

MATH SCA application

This is the complete source code to the SCA MATH waveform. This appendix is divided into several parts, one for each source code file. Each part has a comment attached to it. A picture on the structure of the different components is shown in section 6.2.2 The complete source code together with our hacked version of the OSSIE Core Framework can be found at

IDL and C++ source code

This section contains all of the IDL and C++ source code. In the next section the XML required is presented.

MATH.idl This is the IDL source code which implements all the necessary interfaces. This code is com- piled with the TAO IDL compiler, and CORBA server skeletons and client stubs are created. These are in turn compiled and linked with the MATH application.

/* IDL for the MaTh (Mansour-Thomas) waveform */

#include #include module MATH {

module Common_RT {

/* Instantiate PacketBB from RT API */ /* We’re using an enumeration as ControlType */ /* and a sequence of shorts as PayloadType */

enum ControlType {null, sync};

interface PacketBB {

readonly attribute unsigned short maxPayloadSize; readonly attribute unsigned short minPayloadSize; readonly attribute octet numOfPriorityQueues; 60 Appendix D. MATH SCA application

oneway void pushPacket (in octet priority, in ControlType control, in PortTypes::ShortSequence payload); unsigned short spaceAvailable(in octet priorityQueueID); void enableFlowControl(in boolean enable); void enableEmptySignal(in boolean enable); void setNumOfPriorityQueues(in octet numOfPriorities); };

/* Instantiate SignalsBB from RT API */

interface SignalsBB {

void signalHighWatermark(in octet priorityQueueID); void signalLowWatermark(in octet priorityQueueID); void signalEmpty(); }; };

module Common_NRT {

// Enumeration common for all Resources enum running_t { STANDBY, RUNNING, EXITING }; enum IO_Mode_Type {TRANSMIT_MODE, RECEIVE_MODE};

interface RunningStatus { running_t get_running_status(); };

/* Contruct new API Service Class IOMode */ /* to be able to choose whether we are transmitting */ /* or receiving data */

interface IOMode { void setIOMode (in IO_Mode_Type newIOMode); IO_Mode_Type getIOMode (); }; };

module MAC_RT {

interface DataProcess { void generate_data(); void receive_data(); }; };

module MAC_NRT {

/* Contruct new API Service Class DataMode */ /* to handle different kinds of data */

enum Data_Mode_Type{AUDIO, TEXT};

interface DataMode { void setDataMode(in Data_Mode_Type newDataMode); Data_Mode_Type getDataMode();

}; };

module Physical_RT {

interface Modem { void transmit(); void receive(); }; };

module Physical_NRT { 61

/* Use Transmit_Inhibit from existing NRT API */

interface Transmit_Inhibit { boolean inhibitTransmit (in boolean Inhibit); }; };

/* The "main" interfaces, Physical and MAC, */ /* representing two layers in the SCA API model */ /* and an Assembly Controller. */

interface Physical : CF::Resource, CF::Port, Common_NRT::IOMode, Physical_NRT::Transmit_Inhibit, Common_RT::PacketBB, Common_RT::SignalsBB, Common_NRT::RunningStatus, Physical_RT::Modem {

};

interface MAC : CF::Resource, CF::Port, MAC_NRT::DataMode, MAC_RT::DataProcess, Common_RT::PacketBB, Common_RT::SignalsBB, Common_NRT::RunningStatus, Common_NRT::IOMode {

};

interface AssemblyController : CF::Resource, CF::Port, Common_NRT::RunningStatus { void configure_resource(in string resourceID, in CF::Properties config_properties); }; };

MATH i.h Here is the declaration for the main application.

#ifndef MATH_I_H #define MATH_I_H

#include "wx/wx.h" #include #include "ResourceFactory_i.h" class MATH_Frame : public wxFrame { public: MATH_Frame (const wxString& title, const wxPoint& pos, const wxSize& size);

int MATHinit(); void MATHshutdown();

void close(wxCloseEvent & event);

void OnQuit(wxCommandEvent & event); void OnAbout(wxCommandEvent & event); void OnStart(wxCommandEvent & event); void OnStop(wxCommandEvent & event); void OnInstall(wxCommandEvent & event); void OnUnInstall(wxCommandEvent & event); void OnFileChanged(wxCommandEvent & event); void OnInhibit(wxCommandEvent & event); 62 Appendix D. MATH SCA application

wxCheckBox * inhibitCheckbox; private: CF::DomainManager::ApplicationFactorySequence_var application_factories; CF::Application_ptr OurApp; CORBA::ORB_var orb; DomainManager_impl * ourDM; ResourceFactory_i * ourRF;

MATH::AssemblyController_var _externalPort;

int _app_running; int _app_installed;

}; class MATH_i : public wxApp { public: virtual bool OnInit(); // int OnExit(); private:

MATH_Frame * topFrame;

}; enum { ID_Quit=1, ID_About, ID_Start, ID_Stop, ID_Install, ID_UnInstall, ID_ChangeFile, ID_Transmit_Inhibit };

#endif // MATH_H

MATH.cpp This is the implementation of the main application. Besides setting up the SCA environment, the GUI is included here as well.

// #ifdef MATH_VERBOSE #include // #endif #include "MATH_i.h" using namespace std;

// Macro for the main application. // It includes the main() function // among other things. IMPLEMENT_APP(MATH_i);

// OnInit is the "main" program bool MATH_i::OnInit() {

topFrame = new MATH_Frame("Mansour-Thomas Waveform SCA Interface", wxPoint(50,50), wxSize(350,250));

topFrame->Connect (ID_Quit, wxEVT_COMMAND_MENU_SELECTED, 63

(wxObjectEventFunction) & MATH_Frame::OnQuit); topFrame->Connect (ID_About, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) & MATH_Frame::OnAbout); topFrame->Connect (ID_Start, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) & MATH_Frame::OnStart); topFrame->Connect (ID_Stop, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) & MATH_Frame::OnStop);

topFrame->Connect (ID_Start, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) & MATH_Frame::OnStart); topFrame->Connect (ID_Stop, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) & MATH_Frame::OnStop); topFrame->Connect (ID_Quit, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) & MATH_Frame::OnQuit);

topFrame->Connect (ID_Install, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) & MATH_Frame::OnInstall); topFrame->Connect (ID_UnInstall, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) & MATH_Frame::OnUnInstall);

topFrame->Connect (ID_ChangeFile, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) & MATH_Frame::OnFileChanged); topFrame->Connect (ID_Transmit_Inhibit, wxEVT_COMMAND_CHECKBOX_CLICKED, (wxObjectEventFunction) & MATH_Frame::OnInhibit);

topFrame->Connect (wxID_ANY, wxEVT_CLOSE_WINDOW, (wxObjectEventFunction) & MATH_Frame::close);

topFrame->Show(TRUE); SetTopWindow(topFrame);

return TRUE; } int MATH_Frame::MATHinit() { // Initialize ORB const char * ORBID = "SCA_ORB"; char * orb_argv[1]; orb_argv[0] = "./MATH"; int orb_argc = 1;

orb = CORBA::ORB_init(orb_argc, orb_argv, ORBID);

// Create a Domain Manager ourDM = new DomainManager_impl(); ourDM->init(orb_argc, orb_argv, ORBID);

// Create a ResourceFactory ourRF = new ResourceFactory_i("/DomainName1/ResourceFactory");

// Let the Application pointer point to a "nil" Application Object OurApp = CF::Application::_nil();

return 0; } void MATH_Frame::MATHshutdown() { // Shutdown Resource Factory and destroy object ourRF->shutdown(); delete ourRF;

// Destroy Domain Manager delete ourDM;

// Destroy ORB 64 Appendix D. MATH SCA application

orb->shutdown(true); orb->destroy(); }

MATH_Frame::MATH_Frame (const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame((wxFrame*)NULL,-1,title,pos,size, wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCAPTION , "MATH") { _app_running = 0; _app_installed = 0;

wxBoxSizer * main_sizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer * button_sizer1 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer * button_sizer2 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer * button_sizer3 = new wxBoxSizer(wxHORIZONTAL);

wxString modelist[2] = {"Audio", "Text"};

button_sizer1->Add(new wxButton(this, ID_Start, "Start\nApp", wxPoint(-1, -1)), 0, wxALL, 10); button_sizer1->Add(new wxButton(this, ID_Stop, "Stop\nApp", wxPoint(-1,-1)) , 0, wxALL, 10); button_sizer1->Add(new wxRadioBox(this, -1, "Mode Selection", wxPoint(-1,-1), wxSize(-1,-1), 2, modelist, 1, wxRA_SPECIFY_COLS) , 0, wxALL, 10); button_sizer2->Add(new wxButton(this, ID_Install, "Install\nApp", wxPoint(-1,-1)), 0, wxALIGN_RIGHT|wxALL, 10); button_sizer2->Add(new wxButton(this, ID_UnInstall, "Uninstall\nApp", wxPoint(-1,-1)), 0, wxALIGN_RIGHT|wxALL, 10); button_sizer2->Add(new wxButton(this, ID_ChangeFile, "Change\naudiofile", wxPoint(-1,-1)), 0, wxALIGN_RIGHT|wxALL, 10); button_sizer3->Add(new wxButton(this, ID_Quit, "Quit", wxPoint(-1,-1)), 0, wxALL, 10);

inhibitCheckbox = new wxCheckBox(this, ID_Transmit_Inhibit, "Inhibit Transmission"); button_sizer3->Add(inhibitCheckbox);

main_sizer->Add(button_sizer1, 0, wxALIGN_LEFT); main_sizer->Add(button_sizer2, 0, wxALIGN_LEFT); main_sizer->Add(button_sizer3, 0, wxALIGN_LEFT);

SetSizer(main_sizer);

// create menubar wxMenuBar * menuBar = new wxMenuBar; // create menu wxMenu * menu = new wxMenu; // append menu entries menu->Append(ID_Start, "Start App", "Start Application"); menu->Append(ID_Stop, "Stop App", "Stop Application"); menu->AppendSeparator(); menu->Append(ID_About,"&About...", "Display an about window"); menu->Append(ID_Quit,"E&xit", "Quit this program"); // append menu to menubar menuBar->Append(menu,"&Menu"); // set frame menubar SetMenuBar(menuBar);

// create frame statusbar CreateStatusBar(); // set statusbar text 65

SetStatusText("This is the status bar :)");

MATHinit(); } void MATH_Frame::OnInstall(wxCommandEvent & event) { if (_app_installed == 0) {

SetStatusText("Installing Application, please wait ..."); Refresh(); wxString filename = wxFileSelector("Choose an SAD file to open", "", "", "", "*SAD*", wxOPEN);

if (! filename.empty()) { // Try to install the application on the Domain Manager try {

ourDM->installApplication(filename);

// Get list of ApplicationFactories and the first ApplicationFactory application_factories = ourDM->applicationFactories(); CF::ApplicationFactory_var application_factory = (*application_factories)[0];

CF::Properties AppFacProps(0); CF::DeviceAssignmentSequence DevSeq(0);

// Try to create the Application in ApplicationFactory OurApp = application_factory->create(application_factory->name(), AppFacProps, DevSeq);

// Get a reference to the Assembly Controller for the UI to use. // OSSIE’s implementation of Application::getPort doesn’t follow the // SCA standard (yet), so we don’t have to use external ports in the SAD. CORBA::Object_ptr _port; _port = OurApp->getPort("AssemblyController_NRT_out"); _externalPort = MATH::AssemblyController::_narrow(_port);

SetStatusText("Application installed!"); _app_installed = 1; } catch(CF::InvalidFileName error) { wxString msg = (wxString) error.msg; SetStatusText(msg, 0); } catch(CF::DomainManager::ApplicationInstallationError error) { wxString msg = (wxString) error.msg; SetStatusText(msg, 0); } // Catch all exceptions. catch (...) { SetStatusText("Error in Application installation!"); } } else SetStatusText("Installation cancelled ..."); } else SetStatusText("Application is already installed!"); } void MATH_Frame::OnInhibit(wxCommandEvent & event) { if(_app_installed == 1) {

CORBA::Boolean inhibit;

if (inhibitCheckbox->IsChecked()) { 66 Appendix D. MATH SCA application

inhibit = true; SetStatusText("Transmission is inhibited"); } else { inhibit = false; SetStatusText("Transmission is not inhibited"); } CF::Properties _props; _props.length(1); _props[0].id = CORBA::string_dup("Transmit_Inhibit"); _props[0].value <<= CORBA::Any::from_boolean(inhibit);

_externalPort->configure_resource("MATH_Physical_Resource", _props); } else SetStatusText("Application is not installed"); } void MATH_Frame::OnUnInstall(wxCommandEvent & event) { if (_app_running == 0) { if (_app_installed == 1) { SetStatusText("Uninstalling Application, please wait ..."); Refresh();

CORBA::String_var app_identifier = OurApp->identifier();

// Release Application OurApp->releaseObject(); OurApp = CF::Application::_nil();

// Uninstall Application in Domain Manager. ourDM->uninstallApplication(app_identifier);

SetStatusText("Application uninstalled"); _app_installed = 0; } else SetStatusText("Application is not installed"); } else SetStatusText("Can’t uninstall while Application is running!"); } void MATH_Frame::OnQuit(wxCommandEvent & event) { SetStatusText("Shutting down ..."); Close(TRUE); } void MATH_Frame::OnAbout(wxCommandEvent & WXUNUSED(event)) { SetStatusText("Showing about ..."); wxMessageBox("This is the SCA implementation of the MATH waveform.","About MATH", wxOK|wxICON_INFORMATION, this); } void MATH_Frame::OnFileChanged(wxCommandEvent & WXUNUSED(event)) { if (_app_installed) { wxString filename = wxFileSelector("Choose a new audio file", "", "", "", "*wav*", wxOPEN);

CF::Properties _props; _props.length(1); _props[0].id = CORBA::string_dup("audio_filename"); 67

_props[0].value <<= filename;

_externalPort->configure_resource("MATH_MAC_Resource", _props); SetStatusText("File changed"); } else SetStatusText("Install Application first!"); } void MATH_Frame::OnStart(wxCommandEvent & WXUNUSED(event)) { if (_app_installed == 1) { SetStatusText("Starting Application ... "); Refresh(); OurApp->start(); SetStatusText("Application started."); _app_running = 1; } else SetStatusText("Install Application first."); } void MATH_Frame::OnStop(wxCommandEvent & WXUNUSED(event)) { if (_app_running == 1) { SetStatusText("Stopping Application ... "); Refresh(); OurApp->stop(); SetStatusText("Application has stopped."); _app_running = 0; } else SetStatusText("You haven’t started the Application!"); } void MATH_Frame::close(wxCloseEvent & event) {

if (_app_running == 1) { wxMessageBox("You forgot to stop the Application!", "Hold it right there!", wxOK, this); } else if (_app_installed == 1) { wxMessageBox("You forgot to uninstall the Application!", "Hold it right there!", wxOK, this); } else { SetStatusText("Shutting down ..."); Refresh();

MATHshutdown();

// Destroy frame (close the window and exit) this-Destroy(); } } main.cpp Here is the file containing the main() method for the MAC component. The Physical and AssemblyController has similar main() functions, it only differs by a small amount in the main loop. The CORBA setup is the same.

#include "MATH_MAC_i.h" 68 Appendix D. MATH SCA application

#include #include "orbsvcs/CosNamingC.h" int main( int argc, char** argv ) {

// CORBA Object initializing

const char* ORBID = "SCA_ORB"; char *orb_argv[1]; orb_argv[0] = "./MATH"; int orb_argc = 1;

CORBA::ORB_var orb = CORBA::ORB_init(orb_argc, orb_argv, ORBID);

// Get Root POA CORBA::Object_var poaobj = CORBA::Object::_nil(); while (CORBA::is_nil(poaobj)) poaobj = orb->resolve_initial_references("RootPOA"); PortableServer::POA_var root_poa = PortableServer::POA::_narrow(poaobj.in());

// Activate the POA Manager PortableServer::POAManager_var manager; manager = root_poa->the_POAManager(); manager->activate();

// Create servant MATH_MAC_i mac_i;

// Activate servant and get object reference MATH::MAC_var mac = mac_i._this();

// Get Naming Service CORBA::Object_var nameobj = CORBA::Object::_nil(); while (CORBA::is_nil(nameobj)) nameobj = orb->resolve_initial_references("NameService"); CosNaming::NamingContext_var naming_context = CosNaming::NamingContext::_narrow(nameobj.in());

CosNaming::Name namebinding; namebinding.length(2); namebinding[0].id = CORBA::string_dup ("DomainName1"); namebinding[1].id = CORBA::string_dup ("MATH_MAC");

naming_context->rebind(namebinding, mac.in());

ACE_Time_Value time_out = ACE_Time_Value(0,200);

while (1) {

switch (mac->get_running_status()) {

// Wait until application is started // We need to perform some ORB-related // work in STANDBY mode, such as configuring // and assembling.

case MATH::Common_NRT::STANDBY: if (orb->work_pending()) orb->perform_work(); ACE_OS::sleep(time_out); break;

case MATH::Common_NRT::RUNNING:

mac->generate_data(); ACE_OS::sleep(time_out);

break; 69

case MATH::Common_NRT::EXITING:

naming_context->unbind(namebinding);

PortableServer::ObjectId_var oid = root_poa->reference_to_id(mac); root_poa->deactivate_object(oid);

return 0; } } }

AssemblyController i.h Declaration for the AssemblyController used to control the other parts of the MATH waveform application.

#ifndef ASSEMBLYCONTROLLER_I_H #define ASSEMBLYCONTROLLER_I_H

#include "../MATHS.h" #include class MATH_AssemblyController_i : public virtual POA_MATH::AssemblyController, public virtual POA_CF::Resource, public virtual POA_CF::Port, public Resource_impl { public:

MATH_AssemblyController_i(); ˜MATH_AssemblyController_i();

// Core Framework interfaces:

CORBA::Object_ptr getPort (const char * name) ACE_THROW_SPEC ((CORBA::SystemException, CF::PortSupplier::UnknownPort));

void connectPort (CORBA::Object_ptr connection, const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort, CF::Port::OccupiedPort));

void disconnectPort (const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort));

void start () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StartError));

void stop () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StopError));

void initialize () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::InitializeError));

void releaseObject () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::ReleaseError));

// Waveform interfaces

void configure_resource(const char * resourceID, const CF::Properties & config_properties) ACE_THROW_SPEC ((CORBA::SystemException));

MATH::Common_NRT::running_t get_running_status() ACE_THROW_SPEC ((CORBA::SystemException)); private: 70 Appendix D. MATH SCA application

MATH::Common_NRT::running_t _runningMode;

MATH::MAC_var _MAC_IOPort; MATH::Physical_var _Physical_IOPort;

};

#endif // ASSEMBLYCONTROLLER_I_H

AssemblyController i.cpp AssemblyController implementation.

#include "MATH_AssemblyController_i.h"

// Contructor MATH_AssemblyController_i::MATH_AssemblyController_i() { // Start in STANDBY mode _runningMode = MATH::Common_NRT::STANDBY;

// Initialize object references _MAC_IOPort = MATH::MAC::_nil(); _Physical_IOPort = MATH::Physical::_nil(); }

// Destructor MATH_AssemblyController_i::˜MATH_AssemblyController_i() { }

// Core Framework interfaces:

CORBA::Object_ptr MATH_AssemblyController_i::getPort (const char * name) ACE_THROW_SPEC ((CORBA::SystemException, CF::PortSupplier::UnknownPort)) { if (ACE_OS::strcmp(name, "AssemblyController_NRT_out") == 0) return this->_this(); return CORBA::Object::_nil(); } void MATH_AssemblyController_i::connectPort (CORBA::Object_ptr connection, const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort, CF::Port::OccupiedPort)) { if (ACE_OS::strcmp(connectionId, "AssemblyController_to_Physical") == 0) _Physical_IOPort = MATH::Physical::_narrow(connection); else if (ACE_OS::strcmp(connectionId, "AssemblyController_to_MAC") == 0) _MAC_IOPort = MATH::MAC::_narrow(connection); else throw CF::Port::InvalidPort(); } void MATH_AssemblyController_i::disconnectPort (const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort)) { if (ACE_OS::strcmp(connectionId, "Physical_NRT_in") == 0) _Physical_IOPort = MATH::Physical::_nil(); else if (ACE_OS::strcmp(connectionId, "MAC_NRT_in") == 0) _MAC_IOPort = MATH::MAC::_nil(); } void 71

MATH_AssemblyController_i::initialize () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::InitializeError)) { } void MATH_AssemblyController_i::releaseObject () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::ReleaseError)) { // Let child exit _runningMode = MATH::Common_NRT::EXITING; } void MATH_AssemblyController_i::start () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StartError)) { _runningMode = MATH::Common_NRT::RUNNING;

// Start MAC and Physical _MAC_IOPort->start(); _Physical_IOPort->start(); } void MATH_AssemblyController_i::stop () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StopError)) { _runningMode = MATH::Common_NRT::STANDBY; _MAC_IOPort->stop(); _Physical_IOPort->stop(); }

// Waveform interfaces void MATH_AssemblyController_i::configure_resource(const char * resourceID, const CF::Properties & config_properties) ACE_THROW_SPEC ((CORBA::SystemException)) { if (strcmp(resourceID, "MATH_Physical_Resource") == 0) { if (strcmp(config_properties[0].id, "Transmit_Inhibit") == 0) { CORBA::Boolean inhibit; config_properties[0].value >>= CORBA::Any::to_boolean(inhibit); _Physical_IOPort->inhibitTransmit(inhibit); } else _Physical_IOPort->configure(config_properties); } else if (strcmp(resourceID, "MATH_MAC_Resource") == 0) { _MAC_IOPort->configure(config_properties); } else {

} }

MATH::Common_NRT::running_t MATH_AssemblyController_i::get_running_status() ACE_THROW_SPEC ((CORBA::SystemException)) { return _runningMode; }

MATH Physical i.h Declaration for the Physical layer of the waveform.

#ifndef PHYSICAL_I_H 72 Appendix D. MATH SCA application

#define PHYSICAL_I_H

#include

#include #include "../MATHS.h" #include "../alsa_wrapper/alsa_wrapper.h" #include "../buffer/buffer.h" class MATH_Physical_i : public virtual POA_MATH::Physical, public virtual POA_CF::Resource, public virtual POA_CF::Port, public Resource_impl { public :

MATH_Physical_i (); ˜MATH_Physical_i ();

// Core Framework interfaces:

CORBA::Object_ptr getPort (const char * name) ACE_THROW_SPEC ((CORBA::SystemException, CF::PortSupplier::UnknownPort));

void connectPort (CORBA::Object_ptr connection, const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort, CF::Port::OccupiedPort));

void disconnectPort (const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort));

void start () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StartError));

void stop () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StopError));

void initialize () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::InitializeError));

void releaseObject () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::ReleaseError));

// Waveform interfaces:

void transmit() ACE_THROW_SPEC ((CORBA::SystemException));

void receive() ACE_THROW_SPEC ((CORBA::SystemException));

::MATH::Common_NRT::running_t get_running_status() ACE_THROW_SPEC ((CORBA::SystemException));

void setIOMode (MATH::Common_NRT::IO_Mode_Type newIOMode) ACE_THROW_SPEC ((CORBA::SystemException));

MATH::Common_NRT::IO_Mode_Type getIOMode () ACE_THROW_SPEC ((CORBA::SystemException));

CORBA::Boolean inhibitTransmit (CORBA::Boolean Inhibit) ACE_THROW_SPEC ((CORBA::SystemException));

void pushPacket(CORBA::Octet priority, MATH::Common_RT::ControlType control, const PortTypes::ShortSequence & payload) ACE_THROW_SPEC ((CORBA::SystemException)); 73

CORBA::UShort spaceAvailable(CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException));

void enableFlowControl (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException));

void enableEmptySignal (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException));

void setNumOfPriorityQueues (CORBA::Octet numOfPriorities) ACE_THROW_SPEC ((CORBA::SystemException));

void signalHighWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException));

void signalLowWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException));

void signalEmpty () ACE_THROW_SPEC ((CORBA::SystemException));

// These should be attributes, but TAO IDL compiler generates methods.

CORBA::UShort maxPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException));

CORBA::UShort minPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException));

CORBA::Octet numOfPriorityQueues () ACE_THROW_SPEC ((CORBA::SystemException)); private:

// Waveform attributes:

MATH::MAC_var _MAC_ProvidesPort;

MATH::Common_NRT::running_t _runningMode;

CORBA::UShort _maxPayloadSize; CORBA::UShort _minPayloadSize; CORBA::Octet _numOfPriorityQueues;

CORBA::Boolean _flowControl; CORBA::Boolean _emptySignal;

MATH::Common_NRT::IO_Mode_Type _IOMode; CORBA::Boolean _inhibit;

// Internal attributes: int sent_LowWatermark; int sent_HighWatermark;

buffer * my_buffer; alsa_wrapper * my_alsa; };

#endif // PHYSICAL_I_H

MATH Physical i.cpp Physical layer implementation.

#include "MATH_Physical_i.h"

// Contructor MATH_Physical_i::MATH_Physical_i() { 74 Appendix D. MATH SCA application

// Start in STANDBY mode _runningMode = MATH::Common_NRT::STANDBY;

// Initialize object references _MAC_ProvidesPort = MATH::MAC::_nil(); }

// Destructor MATH_Physical_i::˜MATH_Physical_i() { // Release alsa_wrapper if (my_alsa != NULL) delete my_alsa; // Release buffer if (my_buffer != NULL) delete my_buffer; }

// Core Framework interfaces: CORBA::Object_ptr MATH_Physical_i::getPort (const char * name) ACE_THROW_SPEC ((CORBA::SystemException, CF::PortSupplier::UnknownPort)) { if (ACE_OS::strcmp(name, "Physical_RT_out") == 0) return this->_this(); return CORBA::Object::_nil(); } void MATH_Physical_i::connectPort (CORBA::Object_ptr connection, const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort, CF::Port::OccupiedPort)) { if (ACE_OS::strcmp(connectionId, "Physical_to_MAC") == 0) _MAC_ProvidesPort = MATH::MAC::_narrow(connection); } void MATH_Physical_i::disconnectPort (const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort)) { _MAC_ProvidesPort = MATH::MAC::_nil(); } void MATH_Physical_i::start () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StartError)) { _runningMode = MATH::Common_NRT::RUNNING; } void MATH_Physical_i::stop () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StopError)) { _runningMode = MATH::Common_NRT::STANDBY; my_buffer->reset(); } void MATH_Physical_i::initialize () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::InitializeError)) { // set waveform attributes _maxPayloadSize = 8000; // Maximum of 500 16-bit samples _minPayloadSize = 1000; // Minimum of 125 16-bit samples

_numOfPriorityQueues = 1;

sent_LowWatermark = 0; 75

sent_HighWatermark = 0;

enableFlowControl(true); enableEmptySignal(false);

_IOMode = MATH::Common_NRT::TRANSMIT_MODE; _inhibit = false;

// Set up the alsa_wrapper object, with SND_PCM_STREAM_PLAYBACK // as default mode. // If we want to change direction from output to input, we have to // call alsa_wrapper::shutdownPCM(), then initialize again // with SND_PCM_STREAM_CAPTURE instead.

try { my_alsa = new alsa_wrapper; my_alsa->setmode(SND_PCM_STREAM_PLAYBACK); my_alsa->createPCM(2); // 2 channels } catch (char * errormsg) { _runningMode = MATH::Common_NRT::EXITING; throw (CF::LifeCycle::InitializeError (1)); }

// Create a new buffer from buffer class // to hold the data which comes from MAC layer. my_buffer = new buffer(60 * my_alsa->get_buffer_size()); } void MATH_Physical_i::releaseObject () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::ReleaseError)) { // Let child exit _runningMode = MATH::Common_NRT::EXITING; }

// Real-Time Waveform interfaces: void MATH_Physical_i::pushPacket(CORBA::Octet priority, MATH::Common_RT::ControlType control, const PortTypes::ShortSequence & payload) ACE_THROW_SPEC ((CORBA::SystemException)) { // Put data from MAC in storage buffer my_buffer->insert(payload);

unsigned int b_size = my_buffer->get_size();

if (b_size > 700000) { if (sent_HighWatermark == 0) { _MAC_ProvidesPort->signalHighWatermark(0); sent_HighWatermark = 1; } } else sent_HighWatermark = 0; } void MATH_Physical_i::transmit() ACE_THROW_SPEC ((CORBA::SystemException)) { unsigned int b_size = my_buffer->get_size();

// Send signalLowWatermark if there is a small amount of data in buffer if (b_size < 300000) _MAC_ProvidesPort->signalLowWatermark(0);

unsigned int frames_played; 76 Appendix D. MATH SCA application

unsigned int chunk_size = 2800;

// Try to get ’chunk_size’ chunk of the buffer. // The actual amount is returned in ’chunk_size’. char * chunk_ptr = my_buffer->get_chunk(chunk_size);

// "Send" ’chunk_size’ of data if transmitter is not inhibited // to transmit. if (! _inhibit) frames_played = my_alsa->play(chunk_ptr, chunk_size); } void MATH_Physical_i::receive() ACE_THROW_SPEC ((CORBA::SystemException)) { // Haven’t implemented receiver (yet :) }

CORBA::UShort MATH_Physical_i::spaceAvailable(CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException)) { return my_buffer->get_size(); } void MATH_Physical_i::enableFlowControl (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException)) { _flowControl = enable; } void MATH_Physical_i::enableEmptySignal (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException)) { _emptySignal = enable; } void MATH_Physical_i::setNumOfPriorityQueues (CORBA::Octet numOfPriorities) ACE_THROW_SPEC ((CORBA::SystemException)) { _numOfPriorityQueues = numOfPriorities; } void MATH_Physical_i::signalHighWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException)) { // To implement later in receiver. } void MATH_Physical_i::signalLowWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException)) { // To implement later in receiver. } void MATH_Physical_i::signalEmpty () ACE_THROW_SPEC ((CORBA::SystemException)) { }

// Non-Real-Time Waveform Interfaces: MATH::Common_NRT::running_t MATH_Physical_i::get_running_status() 77

ACE_THROW_SPEC ((CORBA::SystemException)) { return _runningMode; } void MATH_Physical_i::setIOMode (MATH::Common_NRT::IO_Mode_Type newIOMode) ACE_THROW_SPEC ((CORBA::SystemException)) { _IOMode = newIOMode; }

MATH::Common_NRT::IO_Mode_Type MATH_Physical_i::getIOMode () ACE_THROW_SPEC ((CORBA::SystemException)) { return _IOMode; }

CORBA::Boolean MATH_Physical_i::inhibitTransmit (CORBA::Boolean Inhibit) ACE_THROW_SPEC ((CORBA::SystemException)) { _inhibit = Inhibit; // Return true if we succeeded to stop transmission. // In this case, we always do :) return true; }

// These should be attributes, but TAO IDL compiler generates methods. // Workaround, just return a private attribute.

CORBA::UShort MATH_Physical_i::maxPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException)) { return _maxPayloadSize; }

CORBA::UShort MATH_Physical_i::minPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException)) { return _minPayloadSize; }

CORBA::Octet MATH_Physical_i::numOfPriorityQueues () ACE_THROW_SPEC ((CORBA::SystemException)) { return _numOfPriorityQueues; }

MATH MAC i.h Declaration for the MAC layer of the waveform.

#ifndef MAC_I_H #define MAC_I_H

#include

#include #include #include "../MATHS.h" #include class MATH_MAC_i : public virtual POA_MATH::MAC, 78 Appendix D. MATH SCA application

public virtual POA_CF::Resource, public virtual POA_CF::Port, public Resource_impl { public:

MATH_MAC_i (); ˜MATH_MAC_i ();

// Core Framework interfaces:

CORBA::Object_ptr getPort (const char * name) ACE_THROW_SPEC ((CORBA::SystemException, CF::PortSupplier::UnknownPort));

void connectPort (CORBA::Object_ptr connection, const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort, CF::Port::OccupiedPort));

void disconnectPort (const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort));

void start () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StartError));

void stop () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StopError));

void initialize () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::InitializeError));

void releaseObject () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::ReleaseError));

// Waveform interfaces:

void generate_data() ACE_THROW_SPEC ((CORBA::SystemException));

void receive_data() ACE_THROW_SPEC ((CORBA::SystemException));

MATH::Common_NRT::running_t get_running_status() ACE_THROW_SPEC ((CORBA::SystemException));

void setIOMode (MATH::Common_NRT::IO_Mode_Type newIOMode) ACE_THROW_SPEC ((CORBA::SystemException));

MATH::Common_NRT::IO_Mode_Type getIOMode () ACE_THROW_SPEC ((CORBA::SystemException));

void setDataMode (MATH::MAC_NRT::Data_Mode_Type newDataMode) ACE_THROW_SPEC ((CORBA::SystemException));

MATH::MAC_NRT::Data_Mode_Type getDataMode () ACE_THROW_SPEC ((CORBA::SystemException));

void pushPacket(CORBA::Octet priority, MATH::Common_RT::ControlType control, const PortTypes::ShortSequence & payload) ACE_THROW_SPEC ((CORBA::SystemException));

CORBA::UShort spaceAvailable(CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException));

void enableFlowControl (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException));

void enableEmptySignal (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException)); 79

void setNumOfPriorityQueues (CORBA::Octet numOfPriorities) ACE_THROW_SPEC ((CORBA::SystemException));

void signalHighWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException));

void signalLowWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException));

void signalEmpty () ACE_THROW_SPEC ((CORBA::SystemException));

CORBA::UShort maxPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException));

CORBA::UShort minPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException));

CORBA::Octet numOfPriorityQueues () ACE_THROW_SPEC ((CORBA::SystemException)); private:

ORB_WRAP orb;

CF::FileManager_ptr _file_mgr; CF::File_ptr _audiofile;

MATH::Common_NRT::running_t _runningMode;

MATH::Physical_var _Physical_ProvidesPort;

CORBA::UShort _maxPayloadSize; CORBA::UShort _minPayloadSize; CORBA::Octet _numOfPriorityQueues;

CORBA::Boolean _flowControl; CORBA::Boolean _emptySignal;

CORBA::Boolean _send_enable;

CORBA::Boolean _audiofile_is_open;

MATH::MAC_NRT::Data_Mode_Type _datamode; MATH::Common_NRT::IO_Mode_Type _IOMode;

};

#endif // MAC_I_H

MATH MAC i.cpp MAC layer implementation.

#include "MATH_MAC_i.h" using namespace MATH::MAC_NRT;

// Contructor MATH_MAC_i::MATH_MAC_i() { // Start in STANDBY mode _runningMode = MATH::Common_NRT::STANDBY;

// Initialize object reference _Physical_ProvidesPort = MATH::Physical::_nil(); } 80 Appendix D. MATH SCA application

// Destructor MATH_MAC_i::˜MATH_MAC_i() { }

// Core Framework interfaces:

CORBA::Object_ptr MATH_MAC_i::getPort (const char * name) ACE_THROW_SPEC ((CORBA::SystemException, CF::PortSupplier::UnknownPort)) { if (ACE_OS::strcmp(name, "MAC_RT_out") == 0) return this->_this(); return CORBA::Object::_nil(); } void MATH_MAC_i::connectPort (CORBA::Object_ptr connection, const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort, CF::Port::OccupiedPort)) { if (ACE_OS::strcmp(connectionId, "MAC_to_Physical") == 0) _Physical_ProvidesPort = MATH::Physical::_narrow(connection); } void MATH_MAC_i::disconnectPort (const char * connectionId) ACE_THROW_SPEC ((CORBA::SystemException, CF::Port::InvalidPort)) { if (ACE_OS::strcmp(connectionId, "MAC_ProvidesPort") == 0) _Physical_ProvidesPort = MATH::Physical::_nil(); } void MATH_MAC_i::initialize () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::InitializeError)) { // set waveform attributes _maxPayloadSize = 5000; _minPayloadSize = 500;

_numOfPriorityQueues = 1;

_flowControl = false; _emptySignal = false;

_send_enable = false;

_audiofile_is_open = false;

// AUDIO is default data mode. _datamode = AUDIO; // _datamode = TEXT; _IOMode = MATH::Common_NRT::TRANSMIT_MODE;

// Get pointer to FileManager from DomainManager. // FIXME, rewrite ORB lookup CORBA::Object_var dm_object = CORBA::Object::_nil(); while (CORBA::is_nil(dm_object)) dm_object = orb.lookup("/DomainName1/DomainManager");

CF::DomainManager_var dm = CF::DomainManager::_narrow(dm_object); _file_mgr = dm->fileMgr(); } void MATH_MAC_i::releaseObject () ACE_THROW_SPEC ((CORBA::SystemException, CF::LifeCycle::ReleaseError)) { 81

// Let child exit _runningMode = MATH::Common_NRT::EXITING;

// Close file if (_audiofile_is_open) _audiofile->close(); } void MATH_MAC_i::start () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StartError)) { _send_enable = true; _runningMode = MATH::Common_NRT::RUNNING; } void MATH_MAC_i::stop () ACE_THROW_SPEC ((CORBA::SystemException, CF::Resource::StopError)) { _send_enable = false; _runningMode = MATH::Common_NRT::STANDBY; if (_audiofile_is_open) _audiofile->close(); _audiofile_is_open = false; }

// Waveform interfaces void MATH_MAC_i::generate_data() ACE_THROW_SPEC ((CORBA::SystemException)) { // What kind of data should we generate? if (_send_enable) {

switch (_datamode) {

case AUDIO: { if (_audiofile_is_open == false) {

CF::Properties props; props.length(1); props[0].id = CORBA::string_dup("audio_filename");

query(props); const char * _filename; props[0].value >>= _filename;

// Open data file. _audiofile = _file_mgr->open(_filename, true);

// Skip wav header _audiofile->setFilePointer(44);

_audiofile_is_open = true; }

CF::OctetSequence_var _tmpdata; _audiofile->read(_tmpdata, 540);

// End of file? Then set file pointer to beginning of data. if (_tmpdata->length() == 0) { _audiofile->setFilePointer(44); } else {

PortTypes::ShortSequence_var _payload = new PortTypes::ShortSequence; _payload->length(_tmpdata->length()/2); 82 Appendix D. MATH SCA application

// Re-pack the data, going from octets to shorts. for (unsigned int t = 0; t < _payload->length(); t++) { _payload[t] = _tmpdata[t*2]; _payload[t] = _payload[t] << 8; _payload[t] = _payload[t] | _tmpdata[t*2+1]; }

// Priority of this packet sequence. We only have one priority level :) CORBA::Octet prio = 0; // Control information accompanying the sequence. // Not used at this point, just send the ’null’ control field. MATH::Common_RT::ControlType ct = MATH::Common_RT::null;

// Push data to Physical Layer. _Physical_ProvidesPort->pushPacket(prio, ct, _payload); } break; }

case TEXT:

// TEXT is far from implemented. The data has to be modulated in some way // to be able to be transmitted over the sound card without loosing information. // An easy way would be to modulate 1 bit as a 16 bit word, since the sound card // uses 16 bit words. But experiments with the sound card shows this is not // a good idea. A better way to go would be to implement QPSK or BPSK modulating. // All this should of course be handled in Physical Resource. // Below are some remains of the trial-and-error testing with the sound card.

int _ptestsize = 8 * 100;

char * _pteststring = "A small teststring";

PortTypes::ShortSequence_var _payload = new PortTypes::ShortSequence; _payload->length(_ptestsize);

// Priority of this packet sequence. We only have one priority level :) CORBA::Octet prio = 0;

// Set the sync-flag MATH::Common_RT::ControlType ct = MATH::Common_RT::sync;

short one = 0x4000; short zero = 0x9000; char tecken;

for (int c=0; c < _ptestsize; c++) {

// tecken = _pteststring[c];

// for (int i=0; i<=7; i++) { // if ((tecken << i) & 128) // _payload[c*8 + i] = one; // else // _payload[c*8 + i] = zero; // } _payload[c] = one; }

_Physical_ProvidesPort->pushPacket(prio, ct, _payload);

break; } } } void MATH_MAC_i::receive_data() ACE_THROW_SPEC ((CORBA::SystemException)) { 83

// Receiver not implemented (yet) }

MATH::Common_NRT::running_t MATH_MAC_i::get_running_status() ACE_THROW_SPEC ((CORBA::SystemException)) { return _runningMode; } void MATH_MAC_i::setDataMode (MATH::MAC_NRT::Data_Mode_Type newDataMode) ACE_THROW_SPEC ((CORBA::SystemException)) { _datamode = newDataMode; }

MATH::MAC_NRT::Data_Mode_Type MATH_MAC_i::getDataMode () ACE_THROW_SPEC ((CORBA::SystemException)) { return _datamode; } void MATH_MAC_i::setIOMode (MATH::Common_NRT::IO_Mode_Type newIOMode) ACE_THROW_SPEC ((CORBA::SystemException)) { _IOMode = newIOMode; }

MATH::Common_NRT::IO_Mode_Type MATH_MAC_i::getIOMode () ACE_THROW_SPEC ((CORBA::SystemException)) { return _IOMode; } void MATH_MAC_i::pushPacket(CORBA::Octet priority, MATH::Common_RT::ControlType control, const PortTypes::ShortSequence ACE_THROW_SPEC ((CORBA::SystemException)) { // Haven’t implemented receiver. }

CORBA::UShort MATH_MAC_i::spaceAvailable(CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException)) { // Haven’t implemented receiver. return 0; } void MATH_MAC_i::enableFlowControl (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException)) { _flowControl = enable; } void MATH_MAC_i::enableEmptySignal (CORBA::Boolean enable) ACE_THROW_SPEC ((CORBA::SystemException)) { _emptySignal = enable; } void MATH_MAC_i::setNumOfPriorityQueues (CORBA::Octet numOfPriorities) 84 Appendix D. MATH SCA application

ACE_THROW_SPEC ((CORBA::SystemException)) { _numOfPriorityQueues = numOfPriorities; } void MATH_MAC_i::signalHighWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException)) { cout << "MAC got signalHighWatermark" << endl; _send_enable = false; } void MATH_MAC_i::signalLowWatermark (CORBA::Octet priorityQueueID) ACE_THROW_SPEC ((CORBA::SystemException)) { cout << "MAC got signalLowWatermark" << endl; _send_enable = true; } void MATH_MAC_i::signalEmpty () ACE_THROW_SPEC ((CORBA::SystemException)) { _send_enable = true; }

CORBA::UShort MATH_MAC_i::maxPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException)) { return _maxPayloadSize; }

CORBA::UShort MATH_MAC_i::minPayloadSize () ACE_THROW_SPEC ((CORBA::SystemException)) { return _minPayloadSize; }

CORBA::Octet MATH_MAC_i::numOfPriorityQueues () ACE_THROW_SPEC ((CORBA::SystemException)) { return _numOfPriorityQueues; } alsa wrapper.h This class is used to handle the sound card functions, and is used in the Physical layer.

#ifndef ALSA_WRAPPER_H #define ALSA_WRAPPER_H

#include class alsa_wrapper {

public:

alsa_wrapper(); ˜alsa_wrapper();

int play(void * data, int size);

int get_buffer_size(); 85

void setmode(snd_pcm_stream_t newmode); void createPCM(int number_of_channels); void shutdownPCM();

snd_pcm_t * pcm_handle;

private: snd_pcm_hw_params_t * hw_params; snd_pcm_stream_t mode;

snd_pcm_stream_t stream; snd_pcm_uframes_t frames;

int direction; unsigned int bps_value; int buffer_size; };

#endif // ALSA_WRAPPER_H alsa wrapper.cpp ALSA functions implementation.

#include "alsa_wrapper.h"

//#define OPEN_MODE SND_PCM_NONBLOCK #define OPEN_MODE 0

//#define TESTFILE

#ifdef TESTFILE int foo; #endif alsa_wrapper::alsa_wrapper() { #ifdef TESTFILE foo = open("utfil", O_WRONLY | O_APPEND | O_TRUNC); #endif } alsa_wrapper::˜alsa_wrapper() { shutdownPCM();

#ifdef TESTFILE close(foo); #endif } void alsa_wrapper::setmode(snd_pcm_stream_t newmode) { mode = newmode; } void alsa_wrapper::shutdownPCM() { snd_pcm_hw_params_free(hw_params); snd_pcm_drain(pcm_handle); snd_pcm_close(pcm_handle); } void alsa_wrapper::createPCM(int number_of_channels) { 86 Appendix D. MATH SCA application

// A call to setmode() _must_ be done before createPCM()

if (snd_pcm_open(&pcm_handle, "default", mode, OPEN_MODE) < 0) { throw "Error opening PCM device"; }

// Allocate a hardware parameters object. snd_pcm_hw_params_malloc(&hw_params);

// Fill it in with default values. snd_pcm_hw_params_any(pcm_handle, hw_params);

// Set the desired hardware parameters:

// Interleaved mode snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);

// Signed 16-bit little-endian format snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE);

// One channel (mono) snd_pcm_hw_params_set_channels(pcm_handle, hw_params, number_of_channels);

// sample rate if (mode == SND_PCM_STREAM_PLAYBACK) bps_value = 44100; else bps_value = 48000;

direction = 1; snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &bps_value, &direction);

// snd_pcm_hw_params_set_rate(handle, params, &val, &dir);

// Try to set period size. // The actual number of frames is returned in ’frames’. frames = 3999; snd_pcm_hw_params_set_period_size_near(pcm_handle, hw_params, &frames, &direction);

// Write parameters to driver if (snd_pcm_hw_params(pcm_handle, hw_params) < 0) { throw "Unable to set hardware parameters"; }

// Buffer size. // Each frame is 4 bytes (16 bit sample, 2 channels) buffer_size = frames * number_of_channels * 2; } int alsa_wrapper::play(void * data, int size) { #ifdef TESTFILE write(foo, data, size); #endif

int res; res = snd_pcm_writei(pcm_handle, data, size/4);

if (res == -EPIPE) { // EPIPE means underrun. // A call to snd_pcm_prepare fixes the stream. snd_pcm_prepare(pcm_handle); } // Return number of frames played. return res; } int alsa_wrapper::get_buffer_size() { 87

return buffer_size; } buffer.h The buffer class is used in the Physical layer to hold the data coming from MAC layer.

#ifndef BUFFER_H #define BUFFER_H

#include #include "../MATHS.h" class buffer { public:

buffer (size_t size); ˜buffer ();

void insert(const PortTypes::ShortSequence & input); char * get_chunk(unsigned int & size); unsigned int get_size(); void reset(); private: char * _buffer; char * _in_ptr; char * _out_ptr; char * _end_ptr; };

#endif // BUFFER_H buffer.cpp The buffer implementation.

#include "buffer.h"

//Contructor buffer::buffer(size_t size) { _buffer = (char *) malloc(size);

if (_buffer == NULL) throw (CF::LifeCycle::InitializeError (1)); _in_ptr = _buffer; _out_ptr = _buffer; _end_ptr = _buffer + size; }

//Destructor buffer::˜buffer() { if (_buffer != NULL) free(_buffer); } void buffer::insert(const PortTypes::ShortSequence & indata) { // Number of incoming _shorts_ unsigned int indata_size = indata.length(); // Space until end of buffer, measures in _bytes_ unsigned int space_until_end = _end_ptr - _in_ptr; 88 Appendix D. MATH SCA application

// Put incoming data in buffer. // If the incoming data doesn’t fit between the // _in_ptr and the end of buffer, wrap around // to the beginning of the buffer, and put // the rest there. if (indata_size * 2 < space_until_end) { for (unsigned int g = 0; g < indata_size; g++) { _in_ptr[2*g] = indata[g] >> 8; _in_ptr[2*g+1] = indata[g]; } _in_ptr += indata_size * 2; } else if (indata_size * 2 > space_until_end) { for (unsigned int g = 0; g < space_until_end / 2 ; g++) { _in_ptr[2*g] = indata[g] >> 8; _in_ptr[2*g+1] = indata[g]; } _in_ptr = _buffer; for (unsigned int g = 0; g < indata_size - space_until_end / 2; g++) { _in_ptr[2*g] = indata[g + space_until_end / 2] >> 8; _in_ptr[2*g+1] = indata[g + space_until_end / 2]; } _in_ptr += (indata_size - space_until_end / 2) * 2; } // If the data fits _exactly_ up to the end of // the buffer, set _in_ptr to beginning of buffer // after copy. else { for (unsigned int g = 0; g < indata_size; g++) { _in_ptr[2*g] = indata[g] >> 8; _in_ptr[2*g+1] = indata[g]; } _in_ptr = _buffer; } }

// Return a pointer to a chunk of data which is then // assumed to be "consumed" char * buffer::get_chunk(unsigned int & size) { char * tmp = _out_ptr;

if (size > get_size()) size = get_size();

if ((unsigned int) (_end_ptr - _out_ptr) > size) { _out_ptr += size; } else if (_end_ptr - _out_ptr) { size = _end_ptr - _out_ptr; _out_ptr = _buffer; } return tmp; } unsigned int buffer::get_size() { unsigned int size;

if (_in_ptr >= _out_ptr) { size = _in_ptr - _out_ptr; } else { size = _end_ptr - _out_ptr; size += _in_ptr - _buffer; } return size; 89

} void buffer::reset() { _in_ptr = _buffer; _out_ptr = _buffer; }

ResourceFactory i.h Declaration of the ResourceFactory used for our project.

// Implementation of a ResourceFactory.

#ifndef RESOURCEFACTORY_I_H #define RESOURCEFACTORY_I_H

#include "MATHS.h" #include "orb_wrap.h"

#ifdef MATH_VERBOSE #include #endif class ResourceFactory_i : public virtual POA_CF::ResourceFactory { public:

ResourceFactory_i(); ResourceFactory_i(const char* ResourceFactoryName);

˜ResourceFactory_i();

char* identifier() throw (CORBA::SystemException) { return CORBA::string_dup(_identifier); }

CF::Resource_ptr createResource (const char* _resourceID, const CF::Properties& _qualifiers) throw (CF::ResourceFactory::CreateResourceFailure, CORBA::SystemException);

void releaseResource(const char* _rscId) throw (CF::ResourceFactory::InvalidResourceId, CORBA::SystemException);

void shutdown() throw (CF::ResourceFactory::ShutdownFailure, CORBA::SystemException); protected:

CORBA::String_var _name; CORBA::String_var _identifier;

int _numPhysical; int _numMAC; int _numAssemblyController;

MATH::Physical_var _resourcePhysical; MATH::MAC_var _resourceMAC; MATH::AssemblyController_var _resourceAssemblyController;

ORB_WRAP orb;

void init(); 90 Appendix D. MATH SCA application

};

#endif // RESOURCEFACTORY_I_H

ResourceFactory i.cpp Our implementation of a ResourceFactory.

#include "ResourceFactory_i.h"

// Contructor ResourceFactory_i::ResourceFactory_i(const char* ResourceFactoryName) { _numPhysical = 0; _numMAC = 0; _numAssemblyController = 0;

_resourcePhysical = MATH::Physical::_nil(); _resourceMAC = MATH::MAC::_nil(); _resourceAssemblyController = MATH::AssemblyController::_nil();

_name = ResourceFactoryName; // Later˚ identifier vara lika med namnet pa˚ ResourceFactory _identifier = _name;

init(); }

// Destructor ResourceFactory_i::˜ResourceFactory_i() { } void ResourceFactory_i::init() { // Register with POA and Naming Service. try { // Get Root Portable Object Adapter PortableServer::POA_ptr root_poa = orb.getPOA();

// Aktivera objektet i POA och fa˚ Object ID. PortableServer::ObjectId_var oid=root_poa->activate_object(this); CORBA::Object_var rscFacObjReference = root_poa->id_to_reference(oid.in());

// Hamta¨ Naming Context CosNaming::NamingContext_var naming_context = orb.getNamingContext();

// Satt¨ namnet pa˚ objektet som det ska ha i Naming Service CosNaming::Name namebinding; orb.getCosName(namebinding, _name);

// Stoppa in objektet i Naming Service naming_context->rebind(namebinding, rscFacObjReference.in()); } catch (CORBA::Exception & ) { throw CF::Resource::StartError(CF::CFEDOM, "Error in MATH_Physical Constructor"); } }

CF::Resource_ptr ResourceFactory_i::createResource (const char* _rscId, const CF::Properties& qualifiers) throw (CORBA::SystemException, CF::ResourceFactory::CreateResourceFailure) { // This is the hard-coded section of the waveform launcher.

if (strcmp(_rscId, "MATH_Physical_Resource") == 0) { // Is there already a Resource of this type? 91

if (CORBA::is_nil(_resourcePhysical)) { // No, create a new one. int pid;

#ifdef MATH_VERBOSE std::cout << "Starting Physical" << std::endl; #endif // fork process into main and child, if it fails return // a pointer to a _nil()-object. if ((pid = fork()) < 0) return CF::Resource::_nil();

if (pid == 0) // In child process { execl("Physical/Physical", "Physical/Physical", NULL); // If execl returns, there has been an error. #ifdef MATH_VERBOSE std::cout << strerror(errno) << std::endl; #endif exit (-1); }

// In main process:

// Find CORBA object through Naming Service // The child above registers in the Naming Service // so it could take a while before it’s registered.

CORBA::Object_var _obj = CORBA::Object::_nil(); while( CORBA::is_nil(_obj)) _obj = orb.lookup("/DomainName1/MATH_Physical");

// Narrow down from general object to this particular one. _resourcePhysical = MATH::Physical::_narrow(_obj); }

// Increase Resource counter, and return a copy of the // CORBA object. _numPhysical++; return MATH::Physical::_duplicate(_resourcePhysical);

}

if (strcmp(_rscId, "MATH_MAC_Resource") == 0) { if (CORBA::is_nil(_resourceMAC)) { int pid;

#ifdef MATH_VERBOSE std::cout << "Starting MAC" << std::endl; #endif if ((pid = fork()) < 0) return CF::Resource::_nil(); if (pid == 0) { execl("MAC/MAC", "MAC/MAC", NULL); #ifdef MATH_VERBOSE std::cout << strerror(errno) << std::endl; #endif exit (-1); }

CORBA::Object_var _obj = CORBA::Object::_nil(); while( CORBA::is_nil(_obj)) _obj = orb.lookup("/DomainName1/MATH_MAC");

_resourceMAC = MATH::MAC::_narrow(_obj); 92 Appendix D. MATH SCA application

}

_numMAC++; return MATH::MAC::_duplicate(_resourceMAC); }

if (strcmp(_rscId, "MATH_AssemblyController_Resource") == 0) { if (CORBA::is_nil(_resourceAssemblyController)) { int pid;

#ifdef MATH_VERBOSE std::cout << "Starting AssemblyController" << std::endl; #endif if ((pid = fork()) < 0) return CF::Resource::_nil(); if (pid == 0) { execl("AssemblyController/AssemblyController", "AssemblyController/AssemblyController", NULL); #ifdef MATH_VERBOSE std::cout << strerror(errno) << std::endl; #endif exit (-1); }

CORBA::Object_var _obj = CORBA::Object::_nil(); while( CORBA::is_nil(_obj)) _obj = orb.lookup("/DomainName1/MATH_AssemblyController");

_resourceAssemblyController = MATH::AssemblyController::_narrow(_obj); }

_numAssemblyController++; return MATH::AssemblyController::_duplicate(_resourceAssemblyController); }

// Couldn’t create requested Resource, return a nil()-object. return CF::Resource::_nil(); } void ResourceFactory_i::releaseResource (const char* _rscId) throw (CORBA::SystemException, CF::ResourceFactory::InvalidResourceId) { // This is the reverse of createResource, and as such is hard-coded

if (strcmp(_rscId, "MATH_Physical_Resource") == 0) { if (CORBA::is_nil(_resourcePhysical)) return;

// More than one client can be connected to this servant. // As long as the number of Resources "created" // is larger than one, we shouldn’t execute // the releaseObject-method, only decrease counter // until the last client wants to disconnect. // Then we destroy object.

if (_numPhysical > 0) _numPhysical--;

if (_numPhysical == 0) { _resourcePhysical->releaseObject(); // Wait for child to exit int status; 93

wait(&status); _resourcePhysical = MATH::Physical::_nil(); } #ifdef MATH_VERBOSE cout << "Physical has shut down." << endl; #endif }

else if (strcmp(_rscId, "MATH_MAC_Resource") == 0) { if (CORBA::is_nil(_resourceMAC)) return;

if (_numMAC > 0) _numMAC--;

if (_numMAC == 0) { _resourceMAC->releaseObject(); // Wait for child to exit int status; wait(&status); _resourceMAC = MATH::MAC::_nil(); } #ifdef MATH_VERBOSE cout << "MAC has shut down." << endl; #endif }

else if (strcmp(_rscId, "MATH_AssemblyController_Resource") == 0) { if (CORBA::is_nil(_resourceAssemblyController)) return;

if (_numAssemblyController > 0) _numAssemblyController--;

if (_numAssemblyController == 0) { _resourceAssemblyController->releaseObject(); // Wait for child to exit int status; wait(&status); _resourceAssemblyController = MATH::AssemblyController::_nil(); } #ifdef MATH_VERBOSE cout << "AssemblyController has shut down." << endl; #endif } else { throw CF::ResourceFactory::InvalidResourceId(); } } void ResourceFactory_i::shutdown() throw (CORBA::SystemException, CF::ResourceFactory::ShutdownFailure) { _resourcePhysical = MATH::Physical::_nil(); _resourceMAC = MATH::MAC::_nil(); _resourceAssemblyController = MATH::AssemblyController::_nil();

// Remove object from Naming Service and deactivate it in rootPOA PortableServer::POA_ptr root_poa = orb.getPOA(); CosNaming::NamingContext_var naming_context = orb.getNamingContext(); PortableServer::ObjectId_var oid = root_poa->servant_to_id(this);

CosNaming::Name namebinding; orb.getCosName(namebinding, "/DomainName1/ResourceFactory"); 94 Appendix D. MATH SCA application

naming_context->unbind(namebinding);

root_poa->deactivate_object(oid); } 95

Domain Profile XML

These are the XML files needed for our application. Not all files are included, since many of them look quite the same. This section is only here to give an example of how they look like.

MATH SAD.xml The Software Assembly Descriptor describes what kind of components the Application con- sists of, and how they are interconnected. It also states which component is to be the Assem- blyController.

The Mansour-Thomas (MATH) Waveform

96 Appendix D. MATH SCA application

MAC_RT_out Physical_RT_in

Physical_RT_out MAC_RT_in

AssemblyController_NRT_out MAC_NRT_in

AssemblyController_NRT_out 97

Physical_NRT_in

SPD, SCD and PRF files These are the Software Package Descriptor (SPD), Software Component Descriptor (SCD) and Properties Descriptor (PRF) files for the MAC component. These files also exist for each of the Physical, AssemblyController and ResourceFactory components, as well as for the DomainManager.

MAC SPD.xml

Thomas Sundquist

MAC SCD.xml

resource

98 Appendix D. MATH SCA application

MAC PRF.xml

Properties for the MAC Resource File name of audio file to be transmitted /home/ethosun/project/sdr/MATH/audio/spirituals_proclamation.wav