diff --git a/Ccs/ccs_function_lib.py b/Ccs/ccs_function_lib.py index 8e728b758dda4d3bd7a022a5f0c255e00f04aff2..1677e126af5775932d9e2fb2d6269aadef8d98c0 100644 --- a/Ccs/ccs_function_lib.py +++ b/Ccs/ccs_function_lib.py @@ -3079,6 +3079,133 @@ def source_to_srec(data, outfile, memaddr, header=None, bytes_per_line=32, skip_ logger.info('Data written to file: "{}", skipped first {} bytes.'.format(outfile, skip_bytes)) +def srec_direct(fname, memid, pool_name='LIVE', max_pkt_size=MAX_PKT_LEN, tcname=None, sleep=0.125, progress=True, + image_crc=True, byte_align=2, ack=0b1001, dryrun=False): + """ + Upload data from SREC file directly to memory _memid_, no additional segment headers (like for DBS) are added. + @param fname: + @param memid: + @param pool_name: + @param max_pkt_size: + @param tcname: + @param sleep: + @param progress: + @param image_crc: + @param byte_align: + @param ack: + @param dryrun: + @return: + """ + if dryrun: + print('DRYRUN -- NO PACKETS ARE BEING SENT!') + + # get service 6,2 info from MIB + apid, memid_ref, fmt, endspares = _get_upload_service_info(tcname) + pkt_overhead = TC_HEADER_LEN + struct.calcsize(fmt) + len(endspares) + PEC_LEN + payload_len = max_pkt_size - pkt_overhead + + memid = get_mem_id(memid, memid_ref) + + # get permanent pmgr handle to avoid requesting one for each packet + if not dryrun: + pmgr = _get_pmgr_handle(tc_pool=pool_name) + + upload_bytes = b'' + bcnt = 0 + pcnt = 0 + ptot = None + + f = open(fname, 'r').readlines()[1:-1] # omit header and footer line + lines = [p[12:-3] for p in f] + data_size = len(''.join(lines)) // 2 + memaddr = int(f[0][4:12], 16) + + linecount = 0 + nextlinelength = len(lines[linecount]) // 2 + while linecount < len(f) - 1: + + t1 = time.time() + + linepacklist = [] + packlen = 0 + while (packlen + nextlinelength) <= payload_len: + if linecount >= (len(lines) - 1): + break + linepacklist.append(lines[linecount]) + linelength = len(lines[linecount]) // 2 + packlen += linelength + if int(f[linecount + 1][4:12], 16) != (int(f[linecount][4:12], 16) + linelength): + linecount += 1 + newstartaddr = int(f[linecount][4:12], 16) + break + else: + linecount += 1 + newstartaddr = int(f[linecount][4:12], 16) + + nextlinelength = len(lines[linecount]) // 2 + + data = bytes.fromhex(''.join(linepacklist)) + + dlen = len(data) + bcnt += dlen + + # create PUS packet + packetdata = struct.pack(fmt, memid, memaddr, len(data)) + data + endspares + seq_cnt = counters.setdefault(apid, 0) + puspckt = Tcpack(data=packetdata, st=6, sst=2, apid=apid, sc=seq_cnt, ack=ack) + + if len(puspckt) > MAX_PKT_LEN: + logger.warning('Packet length ({}) exceeding MAX_PKT_LEN of {} bytes!'.format(len(puspckt), MAX_PKT_LEN)) + + if not dryrun: + Tcsend_bytes(puspckt, pool_name=pool_name, pmgr_handle=pmgr) + + # collect all uploaded segments for CRC at the end + upload_bytes += data + pcnt += 1 + + if progress: + if ptot is None: + ptot = int(np.ceil(data_size / dlen)) # packets needed to transfer SREC payload + print('{}/{} packets sent\r'.format(pcnt, ptot), end='') + + dt = time.time() - t1 + time.sleep(max(sleep - dt, 0)) + + if data == b'': + print('No data left, exit upload.') + return + + memaddr = newstartaddr + if not dryrun: + counters[apid] += 1 + + # check if entire data is x-byte-aligned + if len(upload_bytes) % byte_align: + padding = byte_align - (len(upload_bytes) % byte_align) + print('\nData is not {}-byte aligned. Sending padding data ({})'.format(byte_align, padding)) + + # create PUS packet + packetdata = struct.pack(fmt, memid, memaddr, padding) + bytes(padding) + endspares + seq_cnt = counters.setdefault(apid, 0) + puspckt = Tcpack(data=packetdata, st=6, sst=2, apid=apid, sc=seq_cnt, ack=ack) + + if not dryrun: + Tcsend_bytes(puspckt, pool_name=pool_name, pmgr_handle=pmgr) + counters[apid] += 1 + + memaddr += padding + upload_bytes += bytes(padding) + bcnt += padding + pcnt += 1 + + print('\nUpload finished, {} bytes sent in {} packets.'.format(bcnt, pcnt)) + + if image_crc: + # return total length of uploaded data (without termination segment) and CRC over entire image, including segment headers + return len(upload_bytes), crc(upload_bytes) + + def _get_upload_service_info(tcname=None): """ Get info about service 6,2 from MIB