I have been following the TinyOS tutorial at this link: http://www.cse.wustl.edu/~lu/cse521s/Slides/tutorial.pdf. I cannot get the final project code to compile in tinyos. I'm using windows xp with cygwin and all the latest rpms. When I try to compile the code with "make micaz" I get and error stating "avr gcc: no file or directory found". Here is the code. thanks in advance.
Makefile:
COMPONENT=DemoAppC
include $(MAKERULES)
DemoMessage.h
#ifndef __DEMOMESSAGE_H
#define __DEMOMESSAGE_H
enum
{
AM_DEMO_MSG = 231,
};
typedef nx_struct demo_msg
{
nx_uint16_t lastReading;
} demo_msg_t;
#endif
DemoP.nc
module DemoP
{
uses interface Boot;
uses interface Leds;
uses interface Read<uint16_t>;
uses interface SplitControl as RadioControl;
uses interface AMSend;
uses interface Receive;
uses interface Packet;
uses interface Timer<TMilli>;
}
implementation
{
message_t buf;
task void readSensor();
task void sendBuffer();
event void Boot.booted()
{
if(call RadioControl.start() != SUCCESS)
call Leds.led0On();
}
event void RadioControl.startDone(error_t err)
{
if(err != SUCCESS)
call Leds.led0On();
if(TOS_NODE_ID == 0)
call Timer.startPeriodic(64);
}
event void Timer.fired()
{
post readSensor();
}
task void readSensor()
{
if(call Read.read() != SUCCESS)
post readSensor();
}
event void Read.readDone(error_t err, uint16_t val)
{
demo_msg_t * payload = (demo_msg_t *)call Packet.getPayload(&buf, sizeof(d
payload->lastReading = val;
post sendBuffer();
}
task void sendBuffer()
{
if(call AMSend.send(AM_BROADCAST_ADDR,
&buf, sizeof(demo_msg_t)) != SUCCESS)
post sendBuffer();
}
event void AMSend.sendDone(message_t * jkdsakljads, error_t err)
{
if(err != SUCCESS)
post sendBuffer();
}
event message_t * Receive.receive(message_t * m,void * payload,uint8_t size)
{
demo_msg_t * dpayload = (demo_msg_t *)payload;
call Leds.set(dpayload->lastReading / 200);
return m;
}
event void RadioControl.stopDone(error_t err) {}
DemoAppC.nc
#include "DemoMessage.h"
configuration DemoAppC{}
implementation{
components DemoP, MainC;
DemoP.Boot -> MainC.Boot;
components LedsC;
DemoP.Leds -> LedsC;
components new HamamatsuS10871TsrC() as PhotoSensor;
DemoP.Read -> PhotoSensor;
components ActiveMessageC;
DemoP.RadioControl -> ActiveMessageC;
components new AMSenderC(AM_DEMO_MSG),
new AMReceiverC(AM_DEMO_MSG);
DemoP.AMSend -> AMSenderC;
DemoP.Receive -> AMReceiverC;
DemoP.Packet -> AMSenderC;
components new TimerMilliC();
DemoP.Timer -> TimerMilliC;
}
I had the same issue. Had to install avr-gcc from https://github.com/osx-cross/homebrew-avr
avr-gcc must not be installed correctly. Make sure you have all of the RPMs from http://docs.tinyos.net/tinywiki/index.php/Manual_installation_using_RPM_packages under the avr section installed.
If rpm -ivh avr-gcc-4.1.2-1.cygwin.i386.rpm returns that the package is already installed then you need to add/usr/bin to your $PATH.
Related
I wrote a small test app to use the Boos Message_Queue to send data between two processes. That all worked correctly and I was able to print the data that I sent.
I moved my test code into my main project and now the main project is not waking from the Receives. The main project runs as systems so I tracked down one error and saw that the message_queue was not checking the same memory location for some reason. I defined BOOST_INTERPROCESS_SHARED_DIR_PATH and then the main project was able to open the queue created by the test app. But when the test app sends the main project never woke from its receive. The main project should be running as system and the test app as a user. But I figured since it is sharing the memory location it should work correctly?
If I open the queue in the test app again it wakes and receives all of the messages right away. Am I missing something or is this a limitation on BOOST message_queue?
The code from the test app:
MessageQueue::MessageQueue(int, boost::interprocess::permissions perm) :
mq(boost::interprocess::create_only, "TestChannel", 100, sizeof(QueueData), perm)
{
}
MessageQueue::MessageQueue(bool) :
mq(boost::interprocess::open_only, "TestChannel")
{
}
MessageQueue::~MessageQueue()
{
int num = mq.get_num_msg();
wprintf(_T("sent: %d\n"), num);
boost::interprocess::message_queue::remove("TestChannel");
}
void MessageQueue::SetCommand(int i)
{
QueueData qd;
qd.fakeInfo = i;
qd.exit = false;
CoCreateGuid(&qd.msgGuid);
mq.send(&qd, sizeof(qd), 0);
OLECHAR* uidOleStr;
if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
// Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
CString guidString(uidOleStr);
CoTaskMemFree(uidOleStr);
wprintf(_T("sent: %d, %s\n"), qd.fakeInfo, guidString);
}
void MessageQueue::WaitForCommand()
{
while(true)
{
QueueData qd;
size_t size, pri;
mq.receive(&qd, sizeof(qd), size, pri);
if (qd.fakeInfo == 2)
sendExit();
OLECHAR* uidOleStr;
if (StringFromCLSID(qd.msgGuid, &uidOleStr) != S_OK)
throw std::runtime_error("Unknown error occurred when trying to convert a GUID to string!");
// Copy the ole str into a CString and then free it immediately, so we don't have to worry about it.
CString guidString(uidOleStr);
CoTaskMemFree(uidOleStr);
wprintf(_T("Recieved: %d, %s\n"), qd.fakeInfo, guidString);
if (qd.exit)
break;
}
}
void MessageQueue::sendExit()
{
QueueData qd;
qd.exit = true;
mq.send(&qd, sizeof(qd), 0);
wprintf(_T("Sent Exit"));
}
.h file:
#pragma once
#define BOOST_INTERPROCESS_SHARED_DIR_PATH "C:\\Program Files (x86)\\Users"
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/interprocess/permissions.hpp>
class QueueData
{
public:
int fakeInfo;
GUID msgGuid;
bool exit;
};
class MessageQueue
{
public:
MessageQueue(int, boost::interprocess::permissions perm);
MessageQueue(bool);
~MessageQueue();
boost::interprocess::message_queue mq;
void SetCommand(int);
void WaitForCommand();
void sendExit();
};
test app running code: (I have been using breakpoints)
void waiter()
{
MessageQueue mq(true);
mq.WaitForCommand();
}
void sender()
{
boost::interprocess::permissions perm;
perm.set_unrestricted();
try
{
boost::interprocess::message_queue::remove("TestChannel");
MessageQueue mq(2, perm);
mq.SetCommand(1);
mq.SetCommand(1);
mq.SetCommand(2);
}
catch (boost::interprocess::interprocess_exception e)
{
}
}
int main() {
waiter();
sender();
}
The code from the main project: (To test I did have it use the wait of the above code and still nothing)
void MemoryChannel::WaitForCmd( const std::function< void ( MemoryChannelCmd cmd, const char *pData, TCHAR *tempPath, GUID msgGuid ) > func )
{
QueueData mcObject;
size_t size, pri;
while (true)
{
pMCD->dataQueue.timed_receive(&mcObject, sizeof(mcObject), size, pri, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(30000));
size_t num = pMCD->dataQueue.get_num_msg();
//func(MemoryChannelCmd::MEMORY_CHANNEL_RUN_SQL_SELECT, "", _T(""), mcObject.msgGuid);
}
}
Doesn't seem to be a code issue since it works in the test app but not in the main project even sharing code.
I am at a loss.
For inter-process communication the higher privilege process must start first. Only then can lower privilege processes can connect.
In your example system process should start the queue, test app connects and then they can communicate. This is why it works when restarting the test app.
It's designed this way to prevent lower privilege users to access higher privilege user memory without permission.
I am working on a Qt GUI that will handle a single client. I am NOT using the Qt TCP libraries or the Qt thread library. I am creating my own Server class (more or less for the experience/learning).
I wanted to make sure what I am doing with the pthread handler isn't going to come back to haunt me in the future. My question is... Is it bad practice to pass this into the pthread_create function? Could this cause problems? It seems to work ok but I am always weary about problems lurking when working with threads.
I will be happy to share more code if it is needed. Thanks for taking a look.
Server.hpp
class Server : public Socket{
public:
....
TCPSocket *accept() throw(SocketException);
static void *listen_for_clients(void *);
void start() throw(SocketException);
void set_listen() throw(SocketException);
private:
pthread_t listen_thread;
};
Server.cpp
void HandleTCPClient(TCPSocket *sock);
TCPSocket *Server::accept() throw(SocketException)
{
int new_conn_sd;
if ( (new_conn_sd = ::accept(socket_descriptor, NULL, 0)) < 0)
{
throw SocketException("Server: accept failed", true);
}
return new TCPSocket(new_conn_sd);
}
void *Server::listen_for_clients(void *ptr)
{
Server * p = (Server *)ptr;
p->set_listen();
for (;;)
{
HandleTCPClient(p->accept());
}
return 0;
}
void Server::start() throw(SocketException)
{
if(pthread_create(&listen_thread, NULL, listen_for_clients, this)) {
throw SocketException("Server: cannot create listen thread", true);
}
}
void Server::set_listen() throw(SocketException)
{
if (listen(socket_descriptor, queue_length) < 0)
{
throw SocketException("Server: set listening socket failed", true);
}
}
void HandleTCPClient(TCPSocket *sock) {
std::cout << "Handling client ";
.....
delete sock;
}
I am trying to connect a C++ Builder app with a .NET service app, and would like the .NET service app to be able to send events back to the C++ Builder app.
Is there a working example of a C++ Builder app which can handle COM events?
There was an error in the DocWiki regarding handling COM Events. I was able to collect some examples from various places, and put them together here for reference.
The .NET application has the following:
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace IPractLib01
{
//
// GUID's to use for the COM objects.
[Guid("ACD03FE3-E506-4D87-BF8B-CC1F52E1FF0C")]
public interface IManagedInterface
{
int SendMessage(
string message
);
}
// Source interface with "event handlers" for COM objects to implement
[Guid("1ACAB463-55A3-4B3F-BE10-6252CDD93CE8")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] // use InterfaceIsDual to get callbacks by other than InvokeEvent()
public interface IIntelliPractEvents
{
[DispId(1)] void MessageReceived();
[DispId(2)] void MessageTextReceived(string message);
}
// Delegates for the events
public delegate void MessageReceivedEventHandler();
public delegate void MessageTextReceivedEventHandler(string message);
[Guid("1F4A7EDA-EE2A-4EA3-B213-A1911C5F766E")]
[ComSourceInterfaces(typeof(IIntelliPractEvents))]
public class IPractLib01Class : IManagedInterface
{
public event MessageReceivedEventHandler MessageReceived;
public event MessageTextReceivedEventHandler MessageTextReceived;
public int SendMessage(string message)
{
if (MessageReceived != null)
{
MessageReceived();
}
if (MessageTextReceived != null)
{
int len = message.Length;
string newMessage = "The message is '" + message + "', and the length of the message is " + len;
MessageTextReceived(newMessage);
}
return 0;
}
}
}
The C++ Builder application contains:
#include "Unit1.h"
#include "IPractLib01_TLB.h" // created with Component/Import Component/Import a Type Library
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// to register the assembly dll:
// regasm IPractLib01.dll /tlb /verbose
// Need to run regasm as administrator, due to need to modify registry. If a regular user login was used to map drives, the mappings are not normally seen by the administrator login. Use "net use" in the administrator login to map them for the administrator
static TCOM_IPractLib01Class iplClass;
// The DocWiki does not take the address of the DIID_, but that does not compile
class MyEventSinkClass : public TEventDispatcher<MyEventSinkClass, &DIID_IIntelliPractEvents>
{
public:
MyEventSinkClass(IUnknown* sourceClass);
~MyEventSinkClass();
// declare the methods of DIID_IIntelliPractEvents here
void __fastcall MessageReceived();
void __fastcall MessageTextReceived(BSTR message/*[in]*/);
virtual HRESULT InvokeEvent(DISPID id, TVariant* params = 0);
IUnknown* theSource_;
};
static MyEventSinkClass* theEventSink = NULL;
static void ConnectNetHandler(void)
{
if (!iplClass)
iplClass = CoIPractLib01Class::Create();
if (!theEventSink) {
theEventSink = new MyEventSinkClass(iplClass);
}
}
// All of the events come through InvokeEvent -- change the interface to InterfaceIsDual if you want events through the other routines
HRESULT MyEventSinkClass::InvokeEvent(DISPID id, TVariant* params)
{
ShowMessage("got InvokeEvent with DISPID " + String(id));
// params would need better handling in a real app
if (params) {
String st = params->operator WideString();
ShowMessage("String is " + st);
}
return 0;
}
MyEventSinkClass::MyEventSinkClass(IUnknown* sourceClass)
{
theSource_ = sourceClass;
ConnectEvents(sourceClass);
}
MyEventSinkClass::~MyEventSinkClass()
{
DisconnectEvents(theSource_);
}
// These two routines do not get called with InterfaceIsDispatch; change that to InterfaceIsDual for these routines to be called.
void __fastcall MyEventSinkClass::MessageReceived()
{
ShowMessage("Message handler received");
}
void __fastcall MyEventSinkClass::MessageTextReceived(BSTR message/*[in]*/)
{
ShowMessage(String("Message handler received with message: ") + message);
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ConnectNetHandler();
long result = -1;
TCOMIManagedInterface mif = iplClass;
if (!mif) {
ShowMessage("Unable to connect to interface");
return;
}
String theMessage = "the message";
mif->SendMessage(WideString(theMessage).c_bstr(), &result);
// check the IErrorInfo
// (Microsoft: Making a COM call that goes through a proxy-stub will clear any existing error object for the calling thread)
IErrorInfo *pperrinfo = NULL;
HRESULT hr = GetErrorInfo(0, &pperrinfo);
if (SUCCEEDED(hr) && pperrinfo) {
WideString wideStringMessage, wideStringDescription; // WideString is a wrapper for BSTR
pperrinfo->GetSource(&wideStringMessage);
pperrinfo->GetDescription(&wideStringDescription);
ShowMessage("Got error from " + String(wideStringMessage) + "; error description: " + String(wideStringDescription));
}
The DLL created by the .NET code must be registered with regasm /tlb to generate the type library, to allow C++ Builder to create the unit to implement COM. However, once the application has been created, regasm does not need to be called on the systems where this is deployed.
I am developing an app which needs to have exclusive access to the USB sound device. I found out that when the music is playing using this device then sometimes it is not possible to get access. So I need to stop and restart CoreAudio daemon.
I am using this piece of code (below) to get it work. But the problem is that after coreaudiod is stopped I can run it only under root user. By default it is ran under _coreaudiod user. How can I run it under _coreaudiod user as it's done by the OS?
#include <CoreFoundation/CFDictionary.h>
#include <Security/Authorization.h>
class ScopedAudioServiceStopper
{
public:
ScopedAudioServiceStopper();
~ScopedAudioServiceStopper();
void stop();
private:
void start();
private:
AuthorizationRef m_authorizationRef;
CFDictionaryRef m_coreAudiodDictionary;
};
ScopedAudioServiceStopper::~ScopedAudioServiceStopper()
{
start();
if (m_coreAudiodDictionary)
CFRelease(m_coreAudiodDictionary);
if (m_authorizationRef)
AuthorizationFree(m_authorizationRef, kAuthorizationFlagDestroyRights);
}
void ScopedAudioServiceStopper::stop()
{
m_coreAudiodDictionary = SMJobCopyDictionary(kSMDomainSystemLaunchd, CFSTR("com.apple.audio.coreaudiod"));
if (!m_coreAudiodDictionary) //means daemon is not started
return;
if (errAuthorizationSuccess != AuthorizationCreate(nullptr, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &m_authorizationRef)) {
m_authorizationRef = nullptr;
return;
}
AuthorizationItem authItem = { kSMRightModifySystemDaemons, 0, nullptr, 0 };
AuthorizationRights authRights = { 1, &authItem };
AuthorizationFlags flags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize |
kAuthorizationFlagExtendRights;
// Obtain the right to install our privileged helper tool (kSMRightModifySystemDaemons).
if (errAuthorizationSuccess != AuthorizationCopyRights(m_authorizationRef, &authRights, kAuthorizationEmptyEnvironment, flags, nullptr)) {
m_authorizationRef = nullptr;
return;
}
CFErrorRef cfError;
if (!SMJobRemove(kSMDomainSystemLaunchd, CFSTR("com.apple.audio.coreaudiod"), m_authorizationRef, TRUE, &cfError)) {
CFRelease(cfError);
}
}
void ScopedAudioServiceStopper::start()
{
if (!m_authorizationRef || !m_coreAudiodDictionary)
return;
CFErrorRef cfError;
if (!SMJobSubmit(kSMDomainSystemLaunchd, m_coreAudiodDictionary, m_authorizationRef, &cfError)) {
CFRelease(cfError);
}
}
On Windows, we generate a PC-specific unique key used to tie a license to a PC. It's a C++ app using wxWidgets, which is theoretically cross-platform compatible but not been maintained on the Mac side. We use some Win32-specific code for generating a key... how might I do something comparable on the Mac?
Looking more into whitelionV and blahdiblah's asnwers, I found this useful page:
Accessing the system serial number programmatically
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
// Returns the serial number as a CFString.
// It is the caller's responsibility to release the returned CFString when done with it.
void CopySerialNumber(CFStringRef *serialNumber)
{
if (serialNumber != NULL) {
*serialNumber = NULL;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
CFTypeRef serialNumberAsCFString =
IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
*serialNumber = serialNumberAsCFString;
}
IOObjectRelease(platformExpert);
}
}
}
Accessing the built-in MAC address programmatically
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetController.h>
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices);
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize);
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices)
{
kern_return_t kernResult;
CFMutableDictionaryRef matchingDict;
CFMutableDictionaryRef propertyMatchDict;
matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
if (NULL == matchingDict) {
printf("IOServiceMatching returned a NULL dictionary.\n");
}
else {
propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (NULL == propertyMatchDict) {
printf("CFDictionaryCreateMutable returned a NULL dictionary.\n");
}
else {
CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
CFRelease(propertyMatchDict);
}
}
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, matchingServices);
if (KERN_SUCCESS != kernResult) {
printf("IOServiceGetMatchingServices returned 0x%08x\n", kernResult);
}
return kernResult;
}
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize)
{
io_object_t intfService;
io_object_t controllerService;
kern_return_t kernResult = KERN_FAILURE;
if (bufferSize < kIOEthernetAddressSize) {
return kernResult;
}
bzero(MACAddress, bufferSize);
while ((intfService = IOIteratorNext(intfIterator)))
{
CFTypeRef MACAddressAsCFData;
kernResult = IORegistryEntryGetParentEntry(intfService,
kIOServicePlane,
&controllerService);
if (KERN_SUCCESS != kernResult) {
printf("IORegistryEntryGetParentEntry returned 0x%08x\n", kernResult);
}
else {
MACAddressAsCFData = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0);
if (MACAddressAsCFData) {
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr
CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
CFRelease(MACAddressAsCFData);
}
(void) IOObjectRelease(controllerService);
}
(void) IOObjectRelease(intfService);
}
return kernResult;
}
int main(int argc, char *argv[])
{
kern_return_t kernResult = KERN_SUCCESS;
io_iterator_t intfIterator;
UInt8 MACAddress[kIOEthernetAddressSize];
kernResult = FindEthernetInterfaces(&intfIterator);
if (KERN_SUCCESS != kernResult) {
printf("FindEthernetInterfaces returned 0x%08x\n", kernResult);
}
else {
kernResult = GetMACAddress(intfIterator, MACAddress, sizeof(MACAddress));
if (KERN_SUCCESS != kernResult) {
printf("GetMACAddress returned 0x%08x\n", kernResult);
}
else {
printf("This system's built-in MAC address is %02x:%02x:%02x:%02x:%02x:%02x.\n",
MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], MACAddress[4], MACAddress[5]);
}
}
(void) IOObjectRelease(intfIterator); // Release the iterator.
return kernResult;
}
While MAC is on the face of it probably preferable as being more predictable, they warn that:
Netbooting introduces a wrinkle with systems with multiple built-in
Ethernet ports. The primary Ethernet port on these systems is the one
that is connected to the NetBoot server. This means that a search for
the primary port may return either of the built-in MAC addresses
depending on which port was used for netbooting. Note that "built-in"
does not include Ethernet ports that reside on an expansion card.
It concerns me this might mean you don't always get the same value back?
You could just call system_profiler and look for "Serial Number"
/usr/sbin/system_profiler | grep "Serial Number (system)"
There might well be a programmatic way to get the same information, but I don't know it offhand.
To uniquely identify any machine you could try to use the MAC address. The process, although not trivial, its quite simple. There are a lot of cross platform open source libraries.
In fact you could try this Apple dev example