5a51117afd34153d194ba9d81bd732f7b083f878
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

1) /* Blinker
2)    Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3)    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4)    a blinkenarea.org project */
5) 
6) #ifndef BLINKER_PHONE_IMPL_H
7) #define BLINKER_PHONE_IMPL_H
8) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

9) #include <sstream>
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

10) #include <string>
11) 
12) #include "Directory.h"
13) #include "File.h"
14) #include "IoCallee.h"
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

15) #include "ListTracker.h"
16) #include "ListTracker_impl.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

17) #include "Mgrs.h"
18) #include "Module.h"
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

19) #include "OpConn.h"
20) #include "OpConnIf.h"
21) #include "OpMgr.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

22) #include "Phone.h"
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

23) #include "PhoneExtension.h"
24) #include "PhoneExtension_impl.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

25) #include "SettingFile.h"
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

26) #include "StringParser.h"
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

27) #include "Time.h"
28) #include "TimeCallee.h"
29) 
30) namespace Blinker {
31) 
32) /**
33)  * @brief constructor
Stefan Schuermans make modules know their name

Stefan Schuermans authored 12 years ago

34)  * @param[in] name module name
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

35)  * @param[in] mgrs managers
36)  * @param[in] dirBase base directory
37)  */
38) template<typename ADDR, typename SOCK>
Stefan Schuermans make modules know their name

Stefan Schuermans authored 12 years ago

39) Phone<ADDR, SOCK>::Phone(const std::string &name, Mgrs &mgrs,
40)                          const Directory &dirBase):
41)   Module(name, mgrs, dirBase),
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

42)   m_fileBind(dirBase.getFile("bind")),
43)   m_fileServer(dirBase.getFile("server")),
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

44)   m_extListTracker(*this, dirBase.getSubdir("extensions")),
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

45)   m_pSock(NULL)
46) {
47)   // read server address
48)   readServer();
49) 
50)   // create and bind socket
51)   createSock();
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

52) 
53)   // load extensions
54)   m_extListTracker.init();
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

55) }
56) 
57) /// virtual destructor
58) template<typename ADDR, typename SOCK>
59) Phone<ADDR, SOCK>::~Phone()
60) {
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

61)   // unload extensions
62)   m_extListTracker.clear();
63) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

64)   // close all connections
65)   while (!m_connLineMap.empty()) {
66)     ConnLineMap::iterator it = m_connLineMap.begin();
67)     it->first->close();
68)     sendHangup(it->second);
69)     m_connLineMap.erase(it);
70)   }
71) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

72)   // destroy socket
73)   destroySock();
74) 
75)   // cancel time callback
76)   m_mgrs.m_callMgr.cancelTimeCall(this);
77) }
78) 
79) /// check for update of configuration
80) template<typename ADDR, typename SOCK>
81) void Phone<ADDR, SOCK>::updateConfig()
82) {
83)   // bind address file was modified -> re-create socket
84)   if (m_fileBind.checkModified()) {
85)     destroySock();
86)     createSock();
87)   }
88) 
89)   // server address file was modified -> re-read server address
90)   if (m_fileServer.checkModified())
91)     readServer();
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

92) 
93)   // extensions update
94)   m_extListTracker.updateConfig();
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

95) }
96) 
97) /// callback when requested time reached
98) template<typename ADDR, typename SOCK>
99) void Phone<ADDR, SOCK>::timeCall()
100) {
101)   Time now = Time::now();
102) 
103)   // server timeout -> re-register
104)   if (m_timeRegister <= now)
105)     sendRegister();
106) 
107)   // send heartbeat
108)   if (m_timeHeartbeat <= now)
109)     sendHeartbeat();
110) }
111) 
112) /**
113)  * @brief callback when I/O object is readable
114)  * @param[in] io I/O object that is readable
115)  */
116) template<typename ADDR, typename SOCK>
117) void Phone<ADDR, SOCK>::ioReadCall(Io *io)
118) {
119)   // reception on socket
120)   if (io == m_pSock)
121)     receiveFromSock();
122) }
123) 
124) /**
125)  * @brief callback when I/O object is writable
126)  * @param[in] io I/O object that is writable
127)  */
128) template<typename ADDR, typename SOCK>
129) void Phone<ADDR, SOCK>::ioWriteCall(Io *io)
130) {
131)   (void)io; // unused
132) }
133) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

134) /**
135)  * @brief operator connection is closed
136)  * @param[in] pConn operator connection object
137)  */
138) template<typename ADDR, typename SOCK>
139) void Phone<ADDR, SOCK>::opConnClose(OpConn *pConn)
140) {
141)   // get phone line of connection
142)   ConnLineMap::iterator itConn = m_connLineMap.find(pConn);
143)   if (itConn == m_connLineMap.end())
144)     return;
145)   unsigned int line = itConn->second;
146) 
147)   // send hangup message
148)   sendHangup(line);
149) 
150)   // remove connection from maps
151)   m_connLineMap.erase(itConn);
152)   m_lineConnMap.erase(line);
153) }
154) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

155) /// (re-)read server address
156) template<typename ADDR, typename SOCK>
157) void Phone<ADDR, SOCK>::readServer()
158) {
159)   m_fileServer.update();
160) 
161)   // register with new server
162)   sendRegister();
163) }
164) 
165) /// create socket and bind it
166) template<typename ADDR, typename SOCK>
167) void Phone<ADDR, SOCK>::createSock()
168) {
169)   // create socket
170)   if (!m_pSock) {
171)     m_pSock = new SOCK();
172)     if (!m_pSock)
173)       return;
174)   }
175) 
176)   // get bind address from bind address setting file
177)   m_fileBind.update();
178)   if (!m_fileBind.m_valid) {
179)     delete m_pSock;
180)     m_pSock = NULL;
181)     return;
182)   }
183) 
184)   // bind socket
185)   if (!m_pSock->bind(m_fileBind.m_obj)) {
186)     delete m_pSock;
187)     m_pSock = NULL;
188)     return;
189)   }
190) 
191)   // request callback on recepetion
192)   m_mgrs.m_callMgr.requestIoReadCall(this, m_pSock);
193) 
194)   // register with server
195)   sendRegister();
196) }
197) 
198) /// destroy socket
199) template<typename ADDR, typename SOCK>
200) void Phone<ADDR, SOCK>::destroySock()
201) {
202)   // cancel callback request
203)   m_mgrs.m_callMgr.cancelIoReadCall(this, m_pSock);
204) 
205)   // destroy socket
206)   if (m_pSock) {
207)     delete m_pSock;
208)     m_pSock = NULL;
209)   }
210) }
211) 
212) /// register with server
213) template<typename ADDR, typename SOCK>
214) void Phone<ADDR, SOCK>::sendRegister()
215) {
216)   send("0:register");
217) 
218)   // set time for next register message and next heartbeat
219)   m_timeRegister = Time::now() + m_serverTimeout;
220)   m_timeHeartbeat = m_timeRegister + m_heartbeatInterval;
221)   updateTimeCallback();
222) }
223) 
224) /// send heartbeat to server
225) template<typename ADDR, typename SOCK>
226) void Phone<ADDR, SOCK>::sendHeartbeat()
227) {
228)   send("0:heartbeat");
229) 
230)   // set time for next heartbeat
231)   m_timeHeartbeat = Time::now() + m_heartbeatInterval;
232)   updateTimeCallback();
233) }
234) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

235) /**
236)  * @brief send hangup message
237)  * @param[in] line number of line to hangup
238)  */
239) template<typename ADDR, typename SOCK>
240) void Phone<ADDR, SOCK>::sendHangup(unsigned int line)
241) {
242)   std::stringstream strm;
243)   strm << line << ":hangup";
244)   send(strm.str());
245) }
246) 
Stefan Schuermans accepting EBIP calls works now

Stefan Schuermans authored 12 years ago

247) /**
248)  * @brief send accept message
249)  * @param[in] line number of line accept on
250)  */
251) template<typename ADDR, typename SOCK>
252) void Phone<ADDR, SOCK>::sendAccept(unsigned int line)
253) {
254)   std::stringstream strm;
255)   strm << line << ":accept";
256)   send(strm.str());
257) }
258) 
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

259) /**
260)  * @brief send message to server
261)  * @param[in] msg message to send
262)  */
263) template<typename ADDR, typename SOCK>
264) void Phone<ADDR, SOCK>::send(const std::string &msg)
265) {
266)   // check that there is a socket and a server address
267)   if (!m_pSock || !m_fileServer.m_valid)
268)     return;
269) 
270)   // send message
271)   m_pSock->send(msg, m_fileServer.m_obj);
272) }
273) 
274) /// receive data from socket
275) template<typename ADDR, typename SOCK>
276) void Phone<ADDR, SOCK>::receiveFromSock()
277) {
278)   std::string msg;
279)   ADDR addr;
280) 
281)   // make sure socket exists
282)   if (!m_pSock)
283)     return;
284) 
285)   // receive (leave if no reception)
286)   if (!m_pSock->recv(msg, addr))
287)     return;
288) 
289)   // check that packet came from server address
290)   if (!m_fileServer.m_valid || addr != m_fileServer.m_obj)
291)     return; // mismatch
292) 
293)   // reset server timeout
294)   m_timeRegister = Time::now() + m_serverTimeout;
295)   updateTimeCallback();
296) 
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

297)   // process message
298)   serverMsg(msg);
299) }
300) 
301) /**
302)  * @brief process message from server
303)  * @param[in] msg message from server
304)  */
305) template<typename ADDR, typename SOCK>
306) void Phone<ADDR, SOCK>::serverMsg(const std::string &msg)
307) {
308)   // get line number and command
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

309)   StringParser parser(msg);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

310)   unsigned int line;
311)   std::string cmd;
312)   if (!parser.uintNo(line) || !parser.fixChr(':') ||
313)       !parser.untilDelim(":", false, cmd))
314)     return;
315) 
316)   // incoming call
317)   if (cmd == "setup") {
318)     std::string caller, extension;
319)     if (!parser.fixChr(':') || !parser.untilDelim(":", true, caller) ||
320)         !parser.fixChr(':') || !parser.untilDelim(":", false, extension))
321)       return;
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

322)     incomingCall(line, extension);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

323)   }
324) 
325)   // hangup
326)   else if (cmd == "onhook") {
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

327)     hangup(line);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

328)   }
329) 
330)   // DTMF symbol (i.e. key pressed)
331)   else if (cmd == "dtmf") {
332)     char key;
333)     if (!parser.fixChr(':') || !parser.oneChrOf("0123456789*#", key))
334)       return;
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

335)     keyPressed(line, key);
Stefan Schuermans implemented extension confi...

Stefan Schuermans authored 12 years ago

336)   }
Stefan Schuermans begin of phone connector

Stefan Schuermans authored 12 years ago

337) }
338) 
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

339) /**
340)  * @brief process incoming call
341)  * @param[in] line number of phone line
342)  * @param[in] extension extenstion called (i.e. phone number)
343)  */
344) template<typename ADDR, typename SOCK>
345) void Phone<ADDR, SOCK>::incomingCall(unsigned int line,
346)                                      const std::string &extension)
347) {
348)   // hangup old call on this line (to be on the safe side)
349)   hangup(line);
350) 
351)   // lookup extension
352)   ExtMap::iterator itExt = m_extMap.find(extension);
353)   if (itExt == m_extMap.end())
354)     return; // unknown extension -> ignore
355) 
356)   // try to open operator connection to module
357)   OpConn *pConn = m_mgrs.m_opMgr.connect(itExt->second, this);
358)   if (!pConn) // module is not ready for connection
359)     return;
360) 
361)   // add connection to maps
362)   m_lineConnMap[line] = pConn;
363)   m_connLineMap[pConn] = line;
Stefan Schuermans accepting EBIP calls works now

Stefan Schuermans authored 12 years ago

364) 
365)   // send accept message
366)   sendAccept(line);
Stefan Schuermans phone connector module basi...

Stefan Schuermans authored 12 years ago

367) }
368) 
369) /**
370)  * @brief hangup on phone line
371)  * @param[in] line number of phone line
372)  */
373) template<typename ADDR, typename SOCK>
374) void Phone<ADDR, SOCK>::hangup(unsigned int line)
375) {
376)   // get connection
377)   LineConnMap::iterator itLine = m_lineConnMap.find(line);
378)   if (itLine == m_lineConnMap.end())
379)     return; // no connection on this line
380)   OpConn *pConn = itLine->second;
381) 
382)   // close connection
383)   pConn->close();
384) 
385)   // remove connection from maps
386)   m_lineConnMap.erase(itLine);
387)   m_connLineMap.erase(pConn);
388) }
389) 
390) /**
391)  * @brief key pressed on phone line
392)  * @param[in] line number of phone line
393)  * @param[in] key key that has been pressed
394)  */
395) template<typename ADDR, typename SOCK>
396) void Phone<ADDR, SOCK>::keyPressed(unsigned int line, char key)
397) {
398)   // get connection
399)   LineConnMap::iterator itLine = m_lineConnMap.find(line);
400)   if (itLine == m_lineConnMap.end())
401)     return; // no connection on this line
402)   OpConn *pConn = itLine->second;
403) 
404)   // TODO
405)   (void)pConn;
406)   (void)key;
407) }
408)