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