1 /*  SpiralSound
2  *  Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #include "ChannelHandler.h"
20 #include <unistd.h>
21 
22 #include <cstdlib>
23 #include <cstring>
24 
25 using namespace std;
26 
SettingsWindow()27 //#define CHANNEL_DEBUG
28 
29 ChannelHandler::ChannelHandler() :
30 m_UpdateIndicator(false)
31 {
32 	m_Mutex = new pthread_mutex_t;
33 	m_Command[0]=0;
34 	m_Command[1]=0;
35 	m_BulkSrc=NULL;
36 	m_BulkSize=0;
37 	m_BulkPos=-1;
38 	pthread_mutex_init(m_Mutex,NULL);
39 }
40 
41 ChannelHandler::~ChannelHandler()
42 {
43     for(map<string,Channel*>::iterator i=m_ChannelMap.begin();
44         i!=m_ChannelMap.end(); i++)
45     {
46 		free(i->second->data_buf);
47         delete i->second;
48     }
49 
50     pthread_mutex_destroy(m_Mutex);
51 	delete m_Mutex;
52 }
53 
54 ///////////////////////////////////////////////////////////////
55 
56 void ChannelHandler::UpdateDataNow()
57 {
58 	#ifdef CHANNEL_DEBUG
59 	cerr<<"Started update"<<endl;
60 	#endif
61 	// make sure the command is cleared even if
62 	// we can't get a lock on the data
63 	m_Command[0]=0;
64 
65     if (pthread_mutex_trylock(m_Mutex))
66     {
67 		#ifdef CHANNEL_DEBUG
68 		cerr<<"Got lock"<<endl;
69 		#endif
70 
71 		m_UpdateIndicator=!m_UpdateIndicator;
72 
73         for(map<string, Channel*>::iterator i=m_ChannelMap.begin();
74             i!=m_ChannelMap.end(); i++)
75         {
76 			Channel *ch = i->second;
77 
78             switch (ch->type)
79 			{
80 				case INPUT :
81             	{
82 					#ifdef CHANNEL_DEBUG
83 					cerr<<"memcpy input channel: ["<<i->first<<"]"<<endl;
84 					#endif
85 	               	memcpy(ch->data,ch->data_buf,ch->size);
86             	} break;
87 
88 				case OUTPUT :
89 			    {
90 					#ifdef CHANNEL_DEBUG
91 					cerr<<"memcpy output channel: ["<<i->first<<"]"<<endl;
92 					#endif
93             	    memcpy(ch->data_buf,ch->data,ch->size);
94             	} break;
95 
96 				// one off request type
97 				case OUTPUT_REQUEST :
98 			    {
99 					if (m_BulkID==i->first && ch->requested)
100 					{
101 						if (m_BulkPos!=-1)
102 						{
103 							// doing a bulk transfer
104 							if (m_BulkPos+ch->size>m_BulkSize)
105 							{
106 								// last transfer
107 								#ifdef CHANNEL_DEBUG
108 								cerr<<"memcpy (last) bulk output channel: ["<<i->first<<"]"<<endl;
109 								cerr<<"pos:"<<m_BulkPos<<" size:"<<m_BulkSize<<" chsize:"<<ch->size<<endl;
110 								#endif
111 								memcpy(ch->data_buf,((char*)m_BulkSrc)+m_BulkPos,m_BulkSize-m_BulkPos);
112 								m_BulkPos=-1;
113 							}
114 							else
115 							{
116 								#ifdef CHANNEL_DEBUG
117 								cerr<<"memcpy bulk output channel: ["<<i->first<<"]"<<endl;
118 								cerr<<"pos:"<<m_BulkPos<<" size:"<<m_BulkSize<<endl;
119 								#endif
120 								memcpy(ch->data_buf,((char*)m_BulkSrc)+m_BulkPos,ch->size);
121 								m_BulkPos+=ch->size;
122 							}
123 							ch->updated=true;
124 							ch->requested=false;
125 						}
126 					}
127 					else
128 					{
129 						// normal request transfer
130 		           	    if (ch->requested)
131 						{
132 							#ifdef CHANNEL_DEBUG
133 							cerr<<"memcpy output channel: ["<<i->first<<"]"<<endl;
134 							#endif
135 							memcpy(ch->data_buf,ch->data,ch->size);
136 							ch->updated=true;
137 							ch->requested=false;
138 						}
139 					}
140             	} break;
141 			}
142         }
143 
144 		m_Command[0]=m_Command[1];
145 		// make sure the command only lasts one update
146 		m_Command[1]=0;
147 
148         pthread_mutex_unlock(m_Mutex);
149 			//cerr<<"audio out mutex"<<endl;
150 
151 		//cerr<<"Update succeeded"<<endl;
152     }
153     else
154     {
155         //cerr<<"Couldn't get lock"<<endl;
156     }
157 
158 	#ifdef CHANNEL_DEBUG
159 	cerr<<"Ended update"<<endl;
160 	#endif
161 }
162 
163 void ChannelHandler::RegisterData(const string &ID, Type t,void* pData, int size)
164 {
165     // probably don't need to lock here, as if get/set are called before
166     // the channels have been set up they won't work anyway, but...
167     //pthread_mutex_lock(m_Mutex);
168 
169 	#ifdef CHANNEL_DEBUG
170 	cerr<<"Registering ["<<ID<<"] "<<hex<<pData<<dec<<" as "<<size<<" bytes big"<<endl;
171 	#endif
172 
173     map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
174     if (i!=m_ChannelMap.end())
~SettingsWindow()175     {
176         cerr<<"Channel with ID ["<<ID<<"] already exists"<<endl;
177     }
178 
cb_Apply_i(Fl_Button * o,void * v)179     Channel *NewCh=new Channel(t);
180     NewCh->data_buf  = malloc(size);
181     NewCh->size      = size;
182     NewCh->data      = pData;
183 	NewCh->requested = false;
184 	NewCh->updated   = false;
185     memcpy(NewCh->data_buf,NewCh->data,size);
186     m_ChannelMap[ID]=NewCh;
187 
188     //pthread_mutex_unlock(m_Mutex);
189 }
190 
191 /////////////////////////////////////////////////////////////////////////
192 
193 void ChannelHandler::GetData(const string &ID, void *data)
cb_Apply(Fl_Button * o,void * v)194 {
195     map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
196     if (i==m_ChannelMap.end())
197     {
198         cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
199         return;
200     }
201 
202     if (!data)
203     {
204         cerr<<"ChannelHandler: Can't copy data to uninitialised mem"<<endl;
205         return;
206     }
207 
208     pthread_mutex_lock(m_Mutex);
209     if (i->second->type==OUTPUT || i->second->type==OUTPUT_REQUEST)
210     {
211         memcpy(data,i->second->data_buf,i->second->size);
212     }
213     else
214     {
215         cerr<<"ChannelHandler: Tried to Get() data registered as input"<<endl;
216     }//cerr<<"unlock 1"<<endl;
217     pthread_mutex_unlock(m_Mutex);
218 }
219 
220 void ChannelHandler::SetData(const string &ID, void *s)
221 {
222     map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
223     if (i==m_ChannelMap.end())
224     {
225         cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
226         return;
227     }
228 
229 //cerr<<"lock 2"<<endl;
230     pthread_mutex_lock(m_Mutex);
231 //cerr<<"lock 2 ok"<<endl;
232     if (i->second->type==INPUT)
233     {
234         memcpy(i->second->data_buf,s,i->second->size);
235     }
236     else
237     {
238         cerr<<"ChannelHandler: Tried to Set() data registered as output"<<endl;
239     }//cerr<<"unlock 2"<<endl;
240     pthread_mutex_unlock(m_Mutex);
241 }
242 
243 void ChannelHandler::SetCommand(char command)
244 {
245 	pthread_mutex_lock(m_Mutex);
246 	m_Command[1]=command;
247 	pthread_mutex_unlock(m_Mutex);
248 }
249 
250 void ChannelHandler::FlushChannels()
251 {
252 	pthread_mutex_lock(m_Mutex);
253 
254 	for(map<string, Channel*>::iterator i=m_ChannelMap.begin();
255        i!=m_ChannelMap.end(); i++)
256     {
257 		memcpy(i->second->data_buf,i->second->data,i->second->size);
258     }
259 
260 	pthread_mutex_unlock(m_Mutex);
261 }
262 
263 void ChannelHandler::RequestChannelAndWait(const string &ID)
264 {
265 	map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
266     if (i==m_ChannelMap.end())
267     {
268         cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
269         return;
270     }
271 
272 	if (i->second->type!=OUTPUT_REQUEST)
273     {
274         cerr<<"ChannelHandler: Trying to request ["<<ID<<"] which is not a requestable channel"<<endl;
275         return;
276     }
277 
278 	pthread_mutex_lock(m_Mutex);
279 	i->second->requested=true;
280 	pthread_mutex_unlock(m_Mutex);
281 
282 	bool ready=false;
283 	while (!ready)
284 	{
285 		usleep(10); // random amount of time :)
286 		pthread_mutex_lock(m_Mutex);
287 		ready=i->second->updated;
288 		pthread_mutex_unlock(m_Mutex);
289 	}
290 
291 	pthread_mutex_lock(m_Mutex);
292 	i->second->requested=false;
293 	i->second->updated=false;
294 	pthread_mutex_unlock(m_Mutex);
295 }
296 
297 void ChannelHandler::BulkTransfer(const string &ID, void *dest, int size)
298 {
299 	map<string,Channel*>::iterator i=m_ChannelMap.find(ID);
300     if (i==m_ChannelMap.end())
301     {
302         cerr<<"ChannelHandler: Channel ["<<ID<<"] does not exist"<<endl;
303         return;
304     }
305 
306 	if (i->second->type!=OUTPUT_REQUEST)
307     {
308         cerr<<"ChannelHandler: Trying to bulk transfer on ["<<ID<<"] which is not a OUTPUT_REQUEST channel"<<endl;
309         return;
310     }
311 
312 	m_BulkPos=0;
313 	m_BulkSize = size;
314 	m_BulkID = ID;
315 
316 	int pos=0;
317 	int buffersize=i->second->size;
318 
319 	// fill up the destination buffer
320 	while (m_BulkPos!=-1)
321 	{
322 		RequestChannelAndWait(ID);
323 		if (pos+buffersize>size)
324 		{
325 			// last copy
326 			char *tempbuf = (char*)malloc(buffersize);
327 			GetData(ID,(void*)tempbuf);
328 			memcpy(((char*)dest)+pos,(void*)tempbuf,size-pos);
329 			free(tempbuf);
330 		}
331 		else
332 		{
333 			GetData(ID,((char*)dest)+pos);
334 		}
335 		pos+=buffersize;
336 	}
337 }
338 
339 void ChannelHandler::Wait()
340 {
341 	bool current;
342 	bool last;
343 
344 	for (int n=0; n<2; n++)
345 	{
346 		pthread_mutex_lock(m_Mutex);
347 		current=m_UpdateIndicator;
348 		last=m_UpdateIndicator;
349 		pthread_mutex_unlock(m_Mutex);
350 
351 		while (current==last)
352 		{
353 			usleep(10);
354 			pthread_mutex_lock(m_Mutex);
355 			current=m_UpdateIndicator;
356 			pthread_mutex_unlock(m_Mutex);
357 		}
358 	}
359 }
360