ondemand ovl load pretty much working

This commit is contained in:
ABelliqueux 2021-04-27 17:12:00 +02:00
parent c7570b6804
commit 077e70dac0
3 changed files with 530 additions and 254 deletions

View File

@ -18,311 +18,566 @@
# - reduced sleeps # - reduced sleeps
# - inc var i with chunkSize # - inc var i with chunkSize
#TODO
# - reduce/remove sleeps
# - keep listening!
import sys import sys
import os
import serial import serial
import time import time
import calendar
import math import math
import signal
DEBUG = 1
# Working directory
cwd = os.getcwd()
levelsFolder = cwd + os.sep + os.sep
# Receive commands from PSX
# ~ Run = True
Listen = 1
uniDebugMode = 0
Command = ""
memAddr = ""
flagAddr = ""
loadFile = ""
# One byte
uno = int(1).to_bytes(1, byteorder='little', signed=False)
data = 0
# ~ dataSize = 0
# Serial connection setup
ser = serial.Serial('/dev/ttyUSB0') ser = serial.Serial('/dev/ttyUSB0')
# Unirom can do 115200 and 510000 ( https://github.com/JonathanDotCel/NOTPSXSerial/blob/bce29e87cb858769fe60eb34d8eb123f9f36c8db/NOTPSXSERIAL.CS#L842 )
ser.baudrate = '115200' ser.baudrate = '115200'
# The data needs to be split in 2K chunks
chunkSize = 2048 chunkSize = 2048
responseBuffer = '' numChunk = 0
address = '800b1470' # We're receiving this info as a string from the psx # checkSum is the checkSum for the full data
# test data checkSum = 0
data = int(111111111111111111111111111111111).to_bytes(14, byteorder='little', signed=False) # If set, it means the data transfer has been initiated
size = len( data ) Transfer = 0
checkSum = 0 # should be 1701 # Delay between write operations. These seem to be needed for the connection not to hang.
Ssbin = 0 sleepTime = 0.08 # Seems like safe minimum
Saddr = 0 def sig_interrupt_handler(signal, frame):
Slen = 0 global Run
def WaitForResponse( expectedAnswer ): Run = False
responseBuffer = "" def setDEBG():
while True: global sleepTime, ser, uniDebugMode
if ser.in_waiting: if DEBUG:
print( "Input buffer : " + str(ser.in_waiting))
chkValue = ser.read(1)
# Make sure byte value is < 128 so that it can be decoded to ascii :: always getting '\xc7' 'q' '\x1c' '\xc7' '\xab' '\xed' '1' '\x05'
if chkValue[0] < 128:
responseBuffer += chkValue.decode('ascii')
else:
responseBuffer += '.'
if len( responseBuffer ) > 4:
# remove first char in buffer
responseBuffer = responseBuffer[1:]
print( "Response buffer : " + responseBuffer )
if responseBuffer == expectedAnswer:
break
print( "Got response : " + responseBuffer + " - " + expectedAnswer )
def main(args):
global checkSum, responseBuffer, Ssbin, Saddr, Slen, chunkSize
# Just to be sure
ser.reset_input_buffer()
ser.reset_output_buffer()
i = 0
while i < len( data ):
checkSum += data[i];
i += 1
print("checkSum : " + str(checkSum) )
# ~ while True:
# ~ global responseBuffer, Ssbin, Saddr, Slen, chunkSize
if not Ssbin:
print("Sending DEBG command...") print("Sending DEBG command...")
ser.write( bytes( 'DEBG' , 'ascii' ) ) ser.write( bytes( 'DEBG' , 'ascii' ) )
time.sleep(.3) time.sleep(sleepTime)
# Empty in waiting buffer to get rid of 'DEBGOKAY' # Empty in waiting buffer
ser.reset_input_buffer() ser.reset_input_buffer()
time.sleep(.5) time.sleep(sleepTime)
uniDebugMode = 1
def WaitForResponse( expectedAnswer ):
# Get incoming data from the serial port in a rolling buffer
# when the content of the buffer corresponds to 'expectedAnswer', returns True
global DEBUG
responseBuffer = ""
success = False
while True:
# If data in serial's incoming buffer
if ser.in_waiting:
# Read 1 byte
byteValue = ser.read(1)
# Make sure byte value is < 128 so that it can be decoded to ascii
if byteValue[0] < 128:
responseBuffer += byteValue.decode('ascii')
else:
responseBuffer += '.'
# Always keep response buffer 4 chars long
if len( responseBuffer ) > 4:
# Remove first char in buffer
responseBuffer = responseBuffer[1:]
# If response is ERR!, checksum check does not check, so check it again
if responseBuffer == "ERR!":
success = False
break
# When expected response shows up, break from the while loop
if responseBuffer == expectedAnswer:
success = True
break
if DEBUG:
print( "Got : " + responseBuffer )
return success
def CalculateChecksum( inBytes, skipFirstSector = False):
returnVal = 0;
i = 0
if skipFirstSector:
i = 2048
while i < len( inBytes ):
returnVal += inBytes[i];
i += 1
return returnVal;
def WriteBytes( inData ):
if DEBUG:
print("Preparing to write bytes...")
global chunkSize, numChunk
# BEGIN WHILE DATA
i = 0
while i < len( inData ):
# BEGIN WHILE TRUE
while True:
# BEGIN TRY/EXCEPT
try:
# Calculate number of 2K chunks we're about to send
numChunk = math.ceil( len( inData ) / chunkSize )
# Calculate current chunk
currentChunk = math.ceil( (i + 1) / chunkSize)
if DEBUG:
print( str ( numChunk + 1 - currentChunk ) + " chunks to send" )
# Avoid going out of range
if ( i + chunkSize ) > len( inData ):
chunkSize = len( inData ) - i
print("Writing chunk " + str( currentChunk ) + " of " + str( numChunk ) )
# ~ ser.write(inData)
chunkChecksum = 0
# Send inData in 2048B chunks
for byte in range( chunkSize ):
# Send byte
ser.write( inData[ i + byte ].to_bytes(1, byteorder='little', signed=False) )
# Calculate chunk checksum
chunkChecksum += inData[ i + byte ]
time.sleep(sleepTime)
if DEBUG:
print( "Chunk cheksum : " + str( chunkChecksum ) )
# Wait for output buffer to be empty
# REMOVE ? Is this needed ?
while ser.out_waiting:
print("*")
wait += 1
time.sleep(sleepTime)
# Wait for unirom to request the checksum
if DEBUG:
print( "Chunk " + str( currentChunk ) + " waiting for unirom to request checksum (CHEK)..." )
WaitForResponse( "CHEK" )
# Send checksum
if DEBUG:
print( "Sending checksum to unirom..." );
# ~ chunkChecksum = 170
bytesChunkChecksum = chunkChecksum.to_bytes( 4, byteorder='little', signed = False )
ser.write( bytesChunkChecksum )
# ~ time.sleep( sleepTime )
if DEBUG:
print( "Waiting for unirom to request more data (MORE)..." )
# Wait for unirom to request MORE inData ( next chunk )
if not WaitForResponse("MORE"):
if DEBUG:
print("ERROR ! Retrying...")
raise Exception()
if DEBUG:
print( str( currentChunk ) + " chunk sent with correct checksum.")
# Increment i from chunkSize
i += chunkSize
except Exception:
continue
# END TRY/EXCEPT
break
# END WHILE TRUE
numChunk = 0
# END WHILE DATA
def SendBin( inData, memAddr ):
global sleepTime
dataSize = len( inData )
if DEBUG:
print("Data size : " + str( dataSize ) )
# Prepare unirom for data reception - sent "SBIN" - received : "OKV2"
if DEBUG:
print("Sending SBIN command...") print("Sending SBIN command...")
ser.write( bytes( 'SBIN' , 'ascii' ) ) ser.write( bytes( 'SBIN' , 'ascii' ) )
time.sleep(.1) time.sleep(sleepTime)
# We're using unirom in debug mode, which means protocol version 2 is available
# Upgrade protocol - sent "UPV2" - received : "OKAY"
ser.write( bytes( 'UPV2' , 'ascii' ) ) ser.write( bytes( 'UPV2' , 'ascii' ) )
Ssbin = 1 time.sleep(sleepTime)
time.sleep(.1) # Initialisation done, set flag
# ~ while True: # ~ Init = 1
#while ser.in_waiting: # From now on, we're using the rolling buffer
# ~ print(".") if DEBUG:
# ~ responseBuffer += ser.read(12).decode('ascii' )
# ~ break
# ~ print( "Buffer : " + responseBuffer )
# ~ if responseBuffer[-4:] == "OKAY":
responseBuffer = ""
print("Waiting for OKAY...") print("Waiting for OKAY...")
WaitForResponse("OKAY") WaitForResponse("OKAY")
# Calculate data checkSum
# convert addr str > int > bytes checkSum = CalculateChecksum( inData )
bytesAddr = int( address, 16 ).to_bytes( 4, byteorder='little', signed=False ) if DEBUG:
# same as ? print("checkSum : " + str(checkSum) )
# ~ hexAddr = bytearray() # Send memory address to load data to, size of data and checkSum
# Unirom expects unsigned longs ( 32bits ), byte endianness little
# ~ hexAddr.append( 0x80) # Convert address from string to integer, then to ulong 32b
# ~ hexAddr.append( 0x0b) bytesAddr = int( memAddr, 16 ).to_bytes( 4, byteorder='little', signed=False )
# ~ hexAddr.append( 0x14) # Write address to serial
# ~ hexAddr.append( 0x70)
# ~ hexAddr.reverse()
# Convert and write address bytes to serial
ser.write( bytesAddr ) ser.write( bytesAddr )
time.sleep(.1) time.sleep(sleepTime)
# Convert and write size bytes to serial # Convert and write int size to serial
bytesSize = size.to_bytes( 4, byteorder='little', signed = False ) bytesSize = dataSize.to_bytes( 4, byteorder='little', signed = False )
ser.write( bytesSize ) ser.write( bytesSize )
time.sleep(.1) time.sleep(sleepTime)
# Convert and write chekSum bytes to serial # Convert and write int chekSum to serial
bytesChk = checkSum.to_bytes( 4, byteorder='little', signed = False ) bytesChk = checkSum.to_bytes( 4, byteorder='little', signed = False )
ser.write( bytesChk ) ser.write( bytesChk )
time.sleep(.1) time.sleep(sleepTime)
# Convert and write data bytes to serial # Send dat data
numChunk = math.ceil( len( data ) / chunkSize ) WriteBytes( inData )
wait = 0 def resetListener():
i = 0 global checkSum, data, Listen, Transfer, dataSize, memAddr, loadFile, flagAddr
while i < len( data ): memAddr = ""
chunkChk = 0 flagAddr = ""
if ( i + chunkSize ) > len( data ): loadFile = ""
chunkSize = len( data ) - i checkSum = 0
print("Writing chunk " + str( i + 1 ) + " of " + str( numChunk ) ) data = 0
# we know data length is < 2048, we'd need some code to cut the data in 2K chunks in real use case dataSize = 0
# ~ print( "Input buffer b : " + str(ser.out_waiting)) Transfer = 0
# ~ print( "Output buffer b : " + str(ser.out_waiting))
# ~ for byte in range( len( data ) ): Listen = 1
ser.write( data ) ser.reset_input_buffer()
# ~ time.sleep(.005) ser.reset_output_buffer()
time.sleep(.1)
# Put chunk checksum calculation here
# Wait for output buffer to be empty def main(args):
while ser.out_waiting: # ~ signal.signal(signal.SIGINT, sig_interrupt_handler)
print("\*") # ~ global Run, memAddr
wait += 1 while True:
time.sleep(.1) global checkSum, chunkSize, data, Listen, Transfer, dataSize, memAddr, loadFile, flagAddr
print("Wait : "+ str(wait)) # Flush serial buffers to avoid residual data
# reset input buffer ser.reset_input_buffer()
# ~ print( "Input buffer : " + str(ser.in_waiting)) ser.reset_output_buffer()
# ~ print( "Output buffer : " + str(ser.out_waiting))
# ~ ser.reset_input_buffer() inputBuffer = ""
# wait for unirom to request the checksum # Listen to incomming connections on serial
print( "Chunk" + str( i + 1 ) + " waiting for unirom to request checksum (CHEK)..." ) if Listen:
WaitForResponse( "CHEK" )
# Wait for "CHEK" - MOVED to WaitForResponse() print("Listening for incoming data...")
# ~ while True: if DEBUG:
# ~ if ser.in_waiting: print("memAddr : " + str(memAddr) + " - loadFile" + loadFile )
# ~ print( "Input buffer : " + str(ser.in_waiting)) while True:
#print(".") # If data on serial, fill buffer
# ~ chkValue = ser.read() while ser.in_waiting:
# ~ # Make sure byte value is < 128 so that it can be decoded to ascii :: always getting '\xc7' 'q' '\x1c' '\xc7' '\xab' '\xed' '1' '\x05' inputBuffer += ser.read().decode('ascii')
# ~ print( "chkVal : " + str(chkValue) + " - " + str( int.from_bytes(chkValue, 'big') ) ) if inputBuffer:
# ~ if int.from_bytes(chkValue, 'big') < 128: if DEBUG == 1:
# ~ responseBuffer += chkValue.decode('ascii') print( "Incoming data : " + inputBuffer )
# ~ if len( responseBuffer ) > 4: # parse command ADDRESS:FILENAME
# ~ # remove first char in buffer parsedBuffer = inputBuffer.split(':')
# ~ responseBuffer = responseBuffer[1:] if inputBuffer.startswith(str(800)):
# ~ print( "Response buffer : " + responseBuffer ) if len( parsedBuffer ) > 2:
# ~ if responseBuffer == "CHEK": memAddr = str(parsedBuffer[0])
# ~ print( "Got response : " + responseBuffer ) flagAddr = str(parsedBuffer[1])
# ~ break loadFile = str(parsedBuffer[2])
print( "Sending checksum to unirom..." ); ser.reset_input_buffer()
ser.write( bytesChk ) inputBuffer = ""
time.sleep( .1 ) if DEBUG:
# Wait for "MORE" - replace with WaitForResponse() print( memAddr + " - " + flagAddr + " - " + loadFile )
# ~ while True: Listen = 0
# ~ if ser.in_waiting: break
# ~ print(".") if memAddr and loadFile:
# ~ responseBuffer += ser.read().decode('ascii') # Remove separator and ';1' at end of the string
# ~ if len( responseBuffer ) > 4: fileClean = loadFile.split(';')[0][1:]
# ~ # remove first char in buffer print("Received addresses and filename : " + memAddr + " - " + flagAddr + " - " + fileClean)
# ~ responseBuffer = responseBuffer[1:] # TODO : replace with a proper level naming scheme
# ~ if responseBuffer == "MORE": binFileName = ""
# ~ print( "Got response : " + responseBuffer ) if fileClean == "level0.bin":
# ~ break binFileName = "Overlay.lvl0"
WaitForResponse("MORE") if fileClean == "level1.bin":
print( str(i+1) + "chunk sent with correct checksum.") binFileName = "Overlay.lvl1"
i += chunkSize if DEBUG:
print(
"Load Data to : " + memAddr + "\n" +
"Reset flag at: " + flagAddr + "\n" +
"File : " + loadFile + "\n" +
"Bin : " + binFileName
)
# Open file as binary if bin filename is defined
if binFileName:
binFile = open( levelsFolder + binFileName, 'rb' )
data = binFile.read()
Transfer = 1
else:
print(" No filename provided, doing nothing ")
resetListener()
# If Init was set, initialize transfer and send data
if Transfer:
print("Initializing data transfer...")
if not uniDebugMode:
# Set unirom to debugmode - sent : "DEBG" - received : "DEBGOKAY"
setDEBG()
# Send level data
SendBin( data, memAddr )
# Set level changed flag
SendBin( uno , flagAddr)
# Reset everything
resetListener()
print("DONE!") print("DONE!")
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':

31
main.c
View File

@ -74,9 +74,9 @@ u_long overlaySize = 0;
#include "levels/level1.h" #include "levels/level1.h"
short level = 1; uint8_t level = 1;
short levelHasChanged = 0; uint16_t levelHasChanged = 0;
static char* overlayFile; static char* overlayFile;
@ -172,17 +172,29 @@ MESH meshPlan = {0};
VECTOR modelPlan_pos = {0}; VECTOR modelPlan_pos = {0};
LEVEL curLvl = { LEVEL curLvl = {
&cmat, &cmat,
&lgtmat, &lgtmat,
(MESH **)&meshes, (MESH **)&meshes,
&meshes_length, &meshes_length,
&actorPtr, &actorPtr,
&levelPtr, &levelPtr,
&propPtr, &propPtr,
&camPtr, &camPtr,
&camPath, &camPath,
(CAMANGLE **)&camAngles, (CAMANGLE **)&camAngles,
&curNode, &curNode,
&meshPlan &meshPlan
}; };
@ -363,17 +375,19 @@ int main() {
#ifdef USECD #ifdef USECD
SwitchLevel( overlayFile, &load_all_overlays_here, &curLvl, &level0); LoadLevelCD( overlayFile, &load_all_overlays_here );
#endif #endif
printf("%p:%s", &load_all_overlays_here, overlayFile); SwitchLevel( overlayFile, &load_all_overlays_here, &curLvl, &level0);
//~ printf("%p:%p:%s", &load_all_overlays_here, &levelHasChanged, overlayFile);
levelHasChanged = 0; levelHasChanged = 0;
} }
FntPrint("Lvl : %s\n", overlayFile); FntPrint("Ovl:%s\nLvlch : %x\nLvl: %x %d", overlayFile, levelHasChanged, &levelHasChanged, level );
//~ FntPrint("%x\n", curLvl.actorPtr->tim); //~ FntPrint("%x\n", curLvl.actorPtr->tim);
@ -1360,10 +1374,17 @@ void callback() {
if (!levelHasChanged){ if (!levelHasChanged){
//~ #ifndef USECD
printf("%p:%p:%s", &load_all_overlays_here, &levelHasChanged, overlayFile);
//~ #endif
level = !level; level = !level;
levelHasChanged = 1; levelHasChanged = 1;
} }
timer = 30; timer = 30;
lastPad = PADL; lastPad = PADL;

2
psx.c
View File

@ -191,7 +191,7 @@ void SwitchLevel(const char*const LevelName, u_long * LoadAddress, LEVEL * curL
ScrRst(); ScrRst();
LoadLevelCD( LevelName, LoadAddress ); //~ LoadLevelCD( LevelName, LoadAddress );
LvlPtrSet( curLevel, loadLevel); LvlPtrSet( curLevel, loadLevel);