forked from w5xd/Digi-Rite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathQsoQueue.cs
192 lines (173 loc) · 8.48 KB
/
QsoQueue.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
using System;
using System.Linq;
namespace DigiRite
{
/* class QsoQueue
* This implementation is specialized to handle the contest exchange
* where there is only one message each to and from the other station
* that has what we need. See Qso2MessageExchange for the other implementation
*
* DigiRite can have multiple QSOs in progress at a time.
* "in progress" means we have either sent or received a message with the
* station, but have not received the required two acknowledgements we
* need. (one for our exchange, the second for "you're in my log")
*
* A QsoInProgress goes into our list based simply on having received
* a message (even unsolicited) or the user clicking on a message
* from someone we want to work.
*
* They are in ordered list of priority.
*
* When we decide to originate a message to such a station, a QsoSequencer
* gets created. It decides what message to send based on what
* acknowledgements we have, so far.
*
* Incoming messages are sent to us based on their ToCall matching myCall.
* We forward each message to the appropriate QsoInProgress based on matching
* hisCall.
*/
class QsoQueue : QueueCommon
{
private IQsoQueueCallBacks callbacks;
public interface IQsoQueueCallBacks
{
string GetExchangeMessage(QsoInProgress q, bool addAck);
string GetAckMessage(QsoInProgress q, bool ofAnAck);
void SendMessage(string toSend, QsoInProgress q, QsoSequencer.MessageSent ms);
void LogQso(QsoInProgress q);
};
// connect the QsoQueue with QsoInProgress on callbacks from the QsoSequencer
protected class QsoSequencerImpl : QsoSequencer.IQsoSequencerCallbacks
{
public QsoSequencerImpl(QsoQueue queue, QsoInProgress q)
{ qsoQueue = queue; qso = q; }
public void LogQso()
{ qsoQueue.logQso(qso); }
public void SendAck(bool ofAnAck, QsoSequencer.MessageSent ms)
{ qsoQueue.sendAck(qso, ofAnAck, ms); }
public void SendExchange(bool withAck, QsoSequencer.MessageSent ms)
{ qsoQueue.sendExchange(qso, withAck, ms); }
public override String ToString()
{ return qso.ToString(); }
private QsoQueue qsoQueue;
private QsoInProgress qso;
}
public QsoQueue(QsosPanel listBox, IQsoQueueCallBacks cb) : base(listBox)
{
callbacks = cb;
}
// call here every for every incoming message that might be relevant to us
public override void MessageForMycall(RecentMessage recentMessage,
bool directlyToMe, string callQsled, short band,
bool autoStart, IsConversationMessage onUsed)
{
XDpack77.Pack77Message.ReceivedMessage rm = recentMessage.Message;
var inProgList = qsosPanel.QsosInProgressDictionary;
QsoInProgress inProgress = null;
bool used = false;
if (inProgList.TryGetValue(QsoInProgress.GetKey(rm, band), out inProgress))
used = inProgress.AddMessageOnMatch(rm, directlyToMe, callQsled);
if (used)
{
// we have an ongoing QSO for this message
QsoSequencer sequencer = inProgress.Sequencer as QsoSequencer;
onUsed(directlyToMe ? Conversation.Origin.TO_ME : Conversation.Origin.TO_OTHER);
// What's in the message? an exchange and/or an acknowledgement?
bool hasExchange = ExchangeFromMessage(rm.Pack77Message) != null;
XDpack77.Pack77Message.Roger roger = rm.Pack77Message as XDpack77.Pack77Message.Roger;
bool ack = false;
if (roger != null)
ack = roger.Roger; // if the message has a roger bit, use it
if (!hasExchange && !ack) // but if no exchange, allow QSL to also set ack
{ // if the message can QSO prior, see if can apply to us
if ((String.Equals("ALL", callQsled) && inProgress.CanAcceptAckNotToMe) ||
String.Equals(myCall,callQsled) ||
String.Equals(myBaseCall, callQsled))
ack = true;
}
if (hasExchange)
sequencer.OnReceivedExchange(ack);
else if (ack)
sequencer.OnReceivedAck();
} else if (autoStart && directlyToMe)
{
onUsed(Conversation.Origin.TO_ME);
// wasn't one we already had. but we autostart with any call
InitiateQso(recentMessage, band, false);
} else if (null != inProgress)
{
if ((null != inProgress.Sequencer) && !inProgress.Sequencer.IsFinished)
onUsed(Conversation.Origin.TO_OTHER); // make it show up in the conversation history
}
}
protected virtual XDpack77.Pack77Message.Exchange ExchangeFromMessage(XDpack77.Pack77Message.Message m)
{
XDpack77.Pack77Message.Exchange exc = m as XDpack77.Pack77Message.Exchange;
// The Pack77Message Exchange interface can be deceptive.
// The Standard message CQ can have this interface but a null exc.Exchange with non-null GridSquare
if (exc != null && !String.IsNullOrEmpty(exc.Exchange))
return exc;
return null;
}
protected override void StartQso(QsoInProgress q)
{ // q needs to already be in our qsosPanel list
QsoSequencer qs = new QsoSequencer(new QsoSequencerImpl(this, q));
q.Sequencer = qs;
// very first message directed from other to me
// can be a CQ I chose to answer, or can be an exchange
XDpack77.Pack77Message.Exchange exc = ExchangeFromMessage(q.Message.Pack77Message);
if (exc != null)
qs.OnReceivedExchange(false);
else
qs.Initiate();
}
private void sendExchange(QsoInProgress q, bool withAck, QsoSequencer.MessageSent ms)
{ callbacks.SendMessage(exchangeMessage(q,withAck), q, ms); }
private string exchangeMessage(QsoInProgress q, bool withAck)
{ return callbacks.GetExchangeMessage(q, withAck); }
private void logQso(QsoInProgress q)
{
callbacks.LogQso(q);
var screenItems = qsosPanel.QsosInProgress;
foreach (QsoInProgress qnext in screenItems)
{
if (qnext.Sequencer == null)
{
StartQso(qnext);
return;
}
}
}
private void sendAck(QsoInProgress q, bool ofAnAck, QsoSequencer.MessageSent ms) /* ofAnAck can be used to send CQ*/
{ callbacks.SendMessage(ackMessage(q,ofAnAck), q, ms); }
private string ackMessage(QsoInProgress q, bool ofAnAck)
{ return callbacks.GetAckMessage(q, ofAnAck); }
}
class QsoQueueGridSquare : QsoQueue
{
protected bool gridSquareAck;
public QsoQueueGridSquare(QsosPanel listBox, IQsoQueueCallBacks cb, bool gridAck) : base(listBox, cb)
{
gridSquareAck = gridAck;
}
protected override void StartQso(QsoInProgress q)
{ // q needs to already be in our qsosPanel list
QsoSequencer qs = new QsoSequencer(new QsoSequencerImpl(this, q));
q.Sequencer = qs;
// very first message directed from other to me
// can be a CQ I chose to answer, or can be an exchange
XDpack77.Pack77Message.Exchange exc = q.Message.Pack77Message as XDpack77.Pack77Message.Exchange;
if (null != ExchangeFromMessage(q.Message.Pack77Message))
qs.OnReceivedExchange(gridSquareAck);
else
qs.Initiate(gridSquareAck && exc != null && exc.GridSquare != null && exc.GridSquare.Length >= 4);
}
protected override XDpack77.Pack77Message.Exchange ExchangeFromMessage(XDpack77.Pack77Message.Message m)
{ // more restrictive than base class. Insist on a grid square
XDpack77.Pack77Message.Exchange exc = base.ExchangeFromMessage(m);
if (exc != null && !String.IsNullOrEmpty(exc.GridSquare) && exc.GridSquare.Length >= 4)
return exc;
return null;
}
}
}