First off, what are the exact places in memory that CalcNet saves and retrieves data? Can you give us the offset from common saferam areas, if applicable?
Second, is there some variable that toggles its value to indicate that CalcNet interrupt is active? If so, what is it?
Thirdly, can other custom interrupts be run while CalcNet's interrupt is running?
ACagliano wrote:
First off, what are the exact places in memory that CalcNet saves and retrieves data? Can you give us the offset from common saferam areas, if applicable?
Check out the slightly-abbreviated Interfacing CALCnet2 page of the DCS wiki, especially the table of memory areas in the Memory Areas section. For the full CALCnet 2.2 documentation, read the CALCnet 2.2 Whitepaper.
Quote:
Second, is there some variable that toggles its value to indicate that CalcNet interrupt is active? If so, what is it?
'Fraid not. If you call Cn2_Setup, you just will have it running (assuming nothing disables it) until you call Cn2_Setdown.
Quote:
Thirdly, can other custom interrupts be run while CalcNet's interrupt is running?
No, unless you chain interrupts by carefully jumping into the Cn2.2 interrupt from yours.
KermMartian wrote:
Quote:
Thirdly, can other custom interrupts be run while CalcNet's interrupt is running?
No, unless you chain interrupts by carefully jumping into the Cn2.2 interrupt from yours.
Would it be possible to actually chain interrupts so that you jump first into the Cn2.2 interrupt, then into another custom interrupt? What sort of coding is required for this?
And, is there a test you can do to determine whether gcn_Setup has been called?
Cn2_Setup, you mean. Be careful not to conflated CALCnet and globalCALCnet: gCn is completely invisible to the attached calculators. The remote calculators appear as local calculators thanks to the bridge's tricks, and any internet services are offered as if coming from other calculators. There's a test you could do to see if data is waiting in the Cn2.2 buffers, and I guess you could poll the memory where the Cn2.2 interrupt stub gets placed, but that would only tell you if the interrupt had been started, not if it had also been recently stopped. You would almost definitely have to chain into the interrupt, not out of it, because you can give it control from anywhere, but it wants to return control to the running program. I suppose you could search through its ~30-byte RAM stub, find the ret, and overwrite that with a jump.
Well then, I guess I need to find out where the Cn2.2 interrupt stub is placed in memory. Is that documented anywhere?
When I get to the part where I would need to deal with jumping from one interrupt to another, would you be willing to assist in that, as I would trust your expertise above my own on how best to handle transitioning.
Another idea:
Instead of looking for the interrupt stub, perhaps I can go about it hookwise...using a hook to intercept the gcn_Setup call and activate the "chain interrupts" routine before actually running gcn_Setup. I don't know if this will work at all, or if it will cause instability with your Cn2.2.
As long as when Cn2_Setup and Cn2_Setdown are called, CALCnet actually gets set up and torn down, respectively, then I see no flaw. The flaw I _can_ see is that the definition of Cn2_Setup and Cn2_Setdown are in Flash on page 0 of Doors CS, so for your latter idea you'd have to unlock and modify Flash.
Well, then I will work with what I have and will report back when I am at this point. Where in memory is the interrupt stub held? And where are the receive buffers held? I think that, to streamline scanning and cause the least slowdown, only the receive buffers need be scanned, not the send buffers.
ACagliano wrote:
Well, then I will work with what I have and will report back when I am at this point. Where in memory is the interrupt stub held? And where are the receive buffers held? I think that, to streamline scanning and cause the least slowdown, only the receive buffers need be scanned, not the send buffers.
The DCS wiki page linked above has the addresses of the receive and send buffers, and the interrupt stub is at $9999.
I was wondering, I need a place to hold data about players on network (calc ID's and 12-bytes worth of location data). Could I create and dynamically edit/expand/shrink an appvar, or should I just use saferam?
Assuming that you answer "use saferam", what is the memory area I should use that will not conflict with Cn2.2, the graph buffer (need it for graphics), or saferam1 (as defined by dcs7.inc) (used for your own data).
It all depends on how much you need to store. In all of my CALCnet-based games, I use safeRAM, since the array only uses a few bytes per player. You're suggesting 12+5 bytes per user; do you have an upper bound on the number of allowed players?
I was figuring on it rejecting more than ten/twenty (maybe twenty) players. Or perhaps a variable max, depending on available RAM. But not an indefinitely large number.
Then, if I reject, there will be issues with broadcast transmission reaching a player that tried to connect, but got rejected (idea: a rejected calc Sets Down Cn).
In my games, all the calculators are peers, so there would be no good way to do that, other than each calculator individually failing to complete the three-way handshake (yes, they do a three-way handshake) when they're full of possibly players. Are you planning a centralized (server + clients) or decentralized (all peers) model? Also, with ten or twenty players, 170-340 bytes can easily fit in one of the remaining safeRAM areas.
Well, can you elaborate on the difference between all peer v. server+clients. If I'm right, I may be combining both. There will be PTP elements (attacks, and text chat) and there will be broadcast elements (position updates, joins, and quits). Am I misunderstanding the question?
Broadcasts vs. direct packets are not the same as peer vs. centralized. With a centralized arrangement, one calculator serves as the server, and all other calculators talk to it in order to request to join the game. With a decentralized arrangement, all calculators handshake with all others, and one is chosen by consensus to be responsible for starting the game.
In short, the server handles all requests. Each calculator is only responsible for changing its own memory, based on data it receives from the server. The first calculator to enter the network starts the game, but when others join, neither is given a higher place in the network. I hope that answers.
Have to eat now. be back in a few.
That makes sense. When you come back, can you tell me how the calculators decide who gets to be the server? Does (for example) each calculator, when it joins, broadcast an "anyone else here?" frame a few times?
Total userland memory usage (per network member)
PlayerDataEntry
Code: CALC ID 5 bytes 0
USERNAME 8 bytes 5
POSITION 12 bytes 13
end 25
Here is the transmission protocol I use (or will use) in the game.
A join message is a 1-byte broadcast transmission, containing the data $01. A joining calculator will broadcast that message for five cycles. When another calc receives this transmission, it writes the sender ID into memory, clears the send buffer, and executes the 'nop' instruction twice, freezing the game for four cycles. This ensures that it will not transmit data for those four cycles. My hope is that this quiets the network, increasing the chance that all calculators receive the broadcast.
Similarly, the first byte in the Send buffer identifies what is being sent. A first byte of $02 is a quit broadcast. It has exactly the same effect as the join message and broadcasts for five cycles. A player may quit either manually, or by having his/her ship destroyed. The only difference is it clears the data for that sender from memory. It then clears the Send buffer, and then freezes for four cycles.
If the first byte is $03, that is a position broadcast. That will update the position of players, with respect to the memory of the executing calculators. That will not cause the receivers to wait, but this message will be broadcast only once every three times around the main loop to prevent network overload.
If the first byte is $04, that is an attack PTP. It will send immediately and the receiver will not wait. It carries only the data about the weapon used to attack. All damage calculations are done on the receiver.
If the first byte is $05, that is a text chat PTP. It will bring up a window at the bottom of your screen and display the received text. It is sent immediately and the receiver will not wait.
That help?
A side question:
We were discussing hooking the Cn2.2 interrupt. Would this work, or do u recommend not doing this:
Code: ; CNHOOK:
; ACagliano:
; Version 1.0:
; 5.10.2011:
; Written for DoorsCS7.0 or higher
.nolist
#include "ti83plus.inc"
#include "dcs7.inc"
.list
RetSave .equ saferam1
.org $9D93
.db $BB,$6D
Init: ;this program only runs with DCS7
xor d ;or with DCS's homerun feature
ret
jr Start
Start:
ld hl,$9999
ld a,$C9
loop:
ld b,(hl)
inc hl
cp b
jr nz,loop
dec hl
ld (RetSave),hl
ld hl,AppVar
b_call(_Mov9toOp1)
ld hl,2
b_call(_CreateAppVar)
ld (de),(RetSave)
inc de
ld (de),(RetSave+1)
ld de,putthis
ex de,hl
ld bc,putthisend-putthis
ldir
putthis:
/code here
putthisend:
AppVar:
.db AppVarObj,"UnHook",0
.end
END
I'm really not clear what that code is even meant to do.
Can you please explain? It looks like you're putting code inside an appvar, for some reason.
KermMartian wrote:
I'm really not clear what that code is even meant to do.
Can you please explain? It looks like you're putting code inside an appvar, for some reason.
haha. It writes the data between putthis and putthisend to the end of the Cn interrupt RAM segment (overwriting the ret), and saves the location of the ret into an appvar, so that the write can be undone.
Words on the transmission protocol??
Regarding the code: yeah, that's actually not bad and might even work, but putting the location in an AppVar is a waste; a two-byte safeRAM area is fine. Also, you haven't bothered doing a Cn2_Setup before you search, so that's not going to work.
Regarding the transmission protocol: I didn't finish reading it through super-thoroughly yet, but you should understand that the broadcast reaching every calculator is not a function of how many cycles you wait anywhere; it's simply whether each of the calculators has Cn2.2 enable, an empty receive buffer, and happens to not be transmitting something itself that will collide in the network. Also, two nops is absolutely minute on the time scale of CALCnet transmission; it's less than a single bit's transmission time.