Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers bdmdriver.cpp Source File

bdmdriver.cpp

00001 /*******************************************************************************
00002 
00003 bdmdriver.cpp
00004 (c) 2014 by Sophie Dexter
00005 
00006 BD32 like 'syscall' processor for BDM resident driver functions
00007 
00008 ********************************************************************************
00009 
00010 WARNING: Use at your own risk, sadly this software comes with no guarantees.
00011 This software is provided 'free' and in good faith, but the author does not
00012 accept liability for any damage arising from its use.
00013 
00014 *******************************************************************************/
00015 
00016 #include "bdmdriver.h"
00017 
00018 FILE *fp = NULL;
00019 
00020 //private functions
00021 bool bdmSyscallPuts (void);
00022 bool bdmSyscallPutchar(void);
00023 bool bdmSyscallGets(void);
00024 bool bdmSyscallGetchar(void);
00025 bool bdmSyscallGetstat(void);
00026 bool bdmSyscallFopen(void);
00027 bool bdmSyscallFclose(void);
00028 bool bdmSyscallFread(void);
00029 bool bdmSyscallFwrite(void);
00030 bool bdmSyscallFtell(void);
00031 bool bdmSyscallFseek(void);
00032 bool bdmSyscallFgets(void);
00033 bool bdmSyscallFputs(void);
00034 bool bdmSyscallEval(void);
00035 bool bdmSyscallFreadsrec(void);
00036 
00037 //-----------------------------------------------------------------------------
00038 /**
00039 Loads the contenst of a uint8_t array into the target's memory starting at the
00040 specified address
00041 
00042 @param        dataArray[]       uint8_t array conataining data for BDM tartget
00043 @param        startAddress      Start address to load BDM memory to
00044 
00045 @return                    succ / fail
00046 */
00047 bool bdmLoadMemory(uint8_t dataArray[], uint32_t startAddress, uint32_t dataArraySize)
00048 {
00049 //    for (uint32_t i = 0; i < sizeof(residentDriver); i++) {
00050 //        if(memwrite_byte(&driverAddress, residentDriver[i]) != TERM_OK) return false;
00051 //        driverAddress++;
00052 //    }
00053     uint32_t driverSize = dataArraySize;
00054     uint32_t driverOffset = 0;
00055     uint32_t driverLong = 0;
00056     uint16_t driverWord = 0;
00057     uint8_t driverByte = 0;
00058     // Check that there is something to send
00059     if (driverSize == 0) return false;
00060     // Send the first 1-4 bytes as efficiently as possible over BDM
00061     switch (driverSize % 4) {
00062         case 3:
00063             driverWord = (dataArray[driverOffset++] << 8) | dataArray[driverOffset++];
00064             if(memwrite_word(&startAddress, driverWord) != TERM_OK) return false;
00065             driverByte = dataArray[driverOffset++];
00066             if(memfill_byte(driverByte) != TERM_OK) return false;
00067             break;
00068         case 2:
00069             driverWord = (dataArray[driverOffset++] << 8) | dataArray[driverOffset++];
00070             if(memwrite_word(&startAddress, driverWord) != TERM_OK) return false;
00071             break;
00072         case 1:
00073             driverByte = dataArray[driverOffset++];
00074             if(memwrite_byte(&startAddress, driverByte) != TERM_OK) return false;
00075             break;
00076         case 0:
00077             for (uint32_t i = 0; i < 4; i++) {
00078                 driverLong <<= 8;
00079                 driverLong |= dataArray[driverOffset++];
00080             }
00081             if(memwrite_long(&startAddress, &driverLong) != TERM_OK) return false;
00082             break;
00083 //        default: // There shouldn't be a default case
00084     }
00085     // transfer the rest as 'longs' to make best use of BDM transfer speed
00086 //    printf("driverOffset 0x%08x, driverSize 0x%08x\r\n", driverOffset, driverSize);
00087     while (driverOffset < driverSize) {
00088         for (uint32_t i = 0; i < 4; i++) {
00089             driverLong <<= 8;
00090             driverLong |= dataArray[driverOffset++];
00091         }
00092         if(memfill_long(&driverLong) != TERM_OK) return false;
00093     }
00094 //    printf("driverOffset 0x%08x, driverSize 0x%08x\r\n", driverOffset, driverSize);
00095     return true;
00096 }
00097 
00098 //-----------------------------------------------------------------------------
00099 /**
00100 Starts a BDM resident driver at the current PC (Program Counter) or a specified
00101 if given. The driver is allowed to run for a maximum period, maxtime, specified
00102 as milliseconds.
00103 
00104 @param        addr        BDM driver address (0 to continue from current PC)
00105 @param        maxtime     how long to allow driver to execute (milliseconds)
00106 
00107 @return                    succ / fail
00108 */
00109 bool bdmRunDriver(uint32_t addr, uint32_t maxtime)
00110 {
00111     // Start BDM driver and allow it up to 200 milliseconds to update 256 Bytes
00112     // Upto 25 pulses per byte, 16us per pulse, 256 Bytes
00113     // 25 * 16 * 256 = 102,400us plus overhead for driver code execution time
00114     // Allowing up to 200 milliseconds seems like a good allowance.
00115     if (run_chip(&addr) != TERM_OK) {
00116         printf("Failed to start BDM driver.\r\n");
00117         return false;
00118     }
00119     timeout.reset();
00120     timeout.start();
00121     // T5 ECUs' BDM interface seem to have problems when the running the CPU and
00122     // sometimes shows the CPU briefly switching between showing BDM mode or that
00123     // the CPU is running.
00124     // I 'debounce' the interface state to workaround this erratic bahaviour
00125     for (uint32_t debounce = 0; debounce < 5; debounce++) {
00126         while (IS_RUNNING) {
00127             debounce = 0;
00128             if (timeout.read_ms() > maxtime) {
00129                 printf("Driver did not return to BDM mode.\r\n");
00130                 timeout.stop();
00131                 return false;
00132             }
00133         }
00134         wait_us(1);
00135     }
00136     timeout.stop();
00137     return true;
00138 }
00139 
00140 
00141 //-----------------------------------------------------------------------------
00142 /**
00143 Starts a BDM resident driver at the current PC (Program Counter) or a specified
00144 if given. The driver is allowed to run for a maximum period, maxtime, specified
00145 as milliseconds.
00146 
00147 @param        addr        BDM driver address (0 to continue from current PC)
00148 @param        maxtime     how long to allow driver to execute (milliseconds)
00149 
00150 @return                    DONE, CONTINUE, ERROR
00151 
00152 */
00153 
00154 uint8_t bdmProcessSyscall(void)
00155 {
00156 
00157     uint32_t syscall = 0xFFFFFFFF;
00158     if (adreg_read(&syscall, 0x0) != TERM_OK) {
00159         printf("Failed to read BDM register.\r\n");
00160         return ERROR;
00161     }
00162     syscall &= 0xFF;
00163 //    printf("SYSCALL 0x%08x\r\n", syscall);
00164     switch (syscall) {
00165         case QUIT:
00166             if (adreg_read(&syscall, 0x1) != TERM_OK) {
00167                 printf("Failed to read BDM register.\r\n");
00168                 return ERROR;
00169             }
00170             return DONE;
00171         case PUTS:
00172             if (!bdmSyscallPuts()) return ERROR;
00173             break;
00174         case PUTCHAR:
00175             if (!bdmSyscallPutchar()) return ERROR;
00176             break;
00177         case GETS:
00178             if (!bdmSyscallGets()) return ERROR;
00179             break;
00180         case GETCHAR:
00181             if (!bdmSyscallGetchar()) return ERROR;
00182             break;
00183         case GETSTAT:
00184             if (!bdmSyscallGetstat()) return ERROR;
00185             break;
00186         case FOPEN:
00187             if (!bdmSyscallFopen()) return ERROR;
00188             break;
00189         case FCLOSE:
00190             if (!bdmSyscallFclose()) return ERROR;
00191             break;
00192         case FREAD:
00193             if (!bdmSyscallFread()) return ERROR;
00194             break;
00195         case FWRITE:
00196             if (!bdmSyscallFwrite()) return ERROR;
00197             break;
00198         case FTELL:
00199             if (!bdmSyscallFtell()) return ERROR;
00200             break;
00201         case FSEEK:
00202             if (!bdmSyscallFseek()) return ERROR;
00203             break;
00204         case FGETS:
00205             if (!bdmSyscallFgets()) return ERROR;
00206             break;
00207         case FPUTS:
00208             if (!bdmSyscallFputs()) return ERROR;
00209             break;
00210         case EVAL:
00211             if (!bdmSyscallEval()) return ERROR;
00212             break;
00213         case FREADSREC:
00214             if (!bdmSyscallFreadsrec()) return ERROR;
00215             break;
00216         default:
00217             printf("!!! Unknown BDM Syscall !!!\r\n");
00218             return ERROR;
00219     }
00220     return CONTINUE;
00221 }
00222 
00223 
00224 bool bdmSyscallPuts()
00225 {
00226     uint32_t bdm_string_address = 0, bdm_return = 0;
00227     if (adreg_read(&bdm_string_address, 0x8) != TERM_OK) {
00228         printf("Failed to read BDM register.\r\n");
00229         return false;
00230     }
00231 // a loop to read chars from BDM into a string
00232     char bdm_string[256];
00233     for (uint32_t i = 0; i < sizeof(bdm_string); i++) {
00234         bdm_string[i] = 0x0;
00235     }
00236     uint32_t i = 0;
00237     do {
00238         if (memread_byte((uint8_t*)(bdm_string+i), &bdm_string_address) != TERM_OK) {
00239             printf("Failed to read BDM memory at address 0x%08x.\r\n", bdm_string_address);
00240             return false;
00241         }
00242         bdm_string_address++;
00243     } while ( (bdm_string[i++] != 0x0) && (i < sizeof(bdm_string)) );
00244 // print the string to stdout (USB virtual serial port)
00245     printf(bdm_string);
00246 // Send BDM return code in D0 (always 0x0 for PUTS)
00247     if (adreg_write(0x0, &bdm_return) != TERM_OK) {
00248         printf("Failed to write BDM register.\r\n");
00249         return false;
00250     }
00251     return true;
00252 }
00253 
00254 bool bdmSyscallPutchar()
00255 {
00256     uint32_t bdm_character = 0, bdm_return = 0;
00257     // read char from BDM
00258     if (adreg_read(&bdm_character, 0x1) != TERM_OK) {
00259         printf("Failed to read BDM register.\r\n");
00260         return false;
00261     }
00262     // print the char to USB virtual serial port
00263     pc.putc((char)bdm_character);
00264     // Send BDM return code in D0 (always 0x0 for PUTCHAR)
00265     if (adreg_write(0x0, &bdm_return) != TERM_OK) {
00266         printf("Failed to write BDM register.\r\n");
00267         return false;
00268     }
00269     return true;
00270 }
00271 
00272 bool bdmSyscallGets()
00273 {
00274     printf("BDM GETS Syscall not supported.\r\n");
00275     return ERROR;
00276 }
00277 
00278 bool bdmSyscallGetchar()
00279 {
00280     // get a char from the USB virtual serial port
00281     uint32_t bdm_return = (uint32_t)pc.getc();
00282     // Send the char to BDM in D0
00283     if (adreg_write(0x0, &bdm_return) != TERM_OK) {
00284         printf("Failed to write BDM register.\r\n");
00285         return false;
00286     }
00287     return true;
00288 }
00289 
00290 bool bdmSyscallGetstat(void)
00291 {
00292     printf("BDM GETSTAT Syscall not supported.\r\n");
00293     return false;
00294 }
00295 
00296 bool bdmSyscallFopen(void)
00297 {
00298     uint32_t bdm_filename_address = 0, bdm_filemode_address = 0;
00299     if (adreg_read(&bdm_filename_address, 0x8) != TERM_OK) {
00300         printf("Failed to read BDM register.\r\n");
00301         return false;
00302     }
00303     if (adreg_read(&bdm_filemode_address, 0x9) != TERM_OK) {
00304         printf("Failed to read BDM register.\r\n");
00305         return false;
00306     }
00307     // a loop to initialise the strings to 0x0
00308     char filename_string[80], filemode_string[5];
00309     uint32_t i = 0;
00310     for (i = 0; i < sizeof(filename_string); i++) {
00311         filename_string[i] = 0x0;
00312     }
00313     for (i = 0; i < sizeof(filemode_string); i++) {
00314         filemode_string[i] = 0x0;
00315     }
00316     i = 0;
00317     // a loop to read chars from BDM into a string
00318     do {
00319         if (memread_byte((uint8_t*)filename_string[i], &bdm_filename_address) != TERM_OK) {
00320             printf("Failed to read BDM memory at address 0x%08x.\r\n", bdm_filename_address);
00321             return false;
00322         }
00323         bdm_filename_address++;
00324     } while ( (filename_string[i++] != 0x0) && (i < sizeof(filename_string)) );
00325     do {
00326         if (memread_byte((uint8_t*)filemode_string[i], &bdm_filemode_address) != TERM_OK) {
00327             printf("Failed to read BDM memory at address 0x%08x.\r\n", bdm_filemode_address);
00328             return false;
00329         }
00330         bdm_filemode_address++;
00331     } while ( (filemode_string[i++] != 0x0) && (i < sizeof(filemode_string)) );
00332     // Open the file
00333     fp = fopen(filename_string, filemode_string);    // Open "modified.hex" on the local file system for reading
00334     // Send BDM return code in D0
00335     if (adreg_write(0x0, (uint32_t*)fp) != TERM_OK) {
00336         printf("Failed to write BDM register.\r\n");
00337         return false;
00338     }
00339     return true;
00340 }
00341 
00342 bool bdmSyscallFclose(void)
00343 {
00344     uint32_t close_result = fclose(fp);
00345     // Send BDM return code in D0
00346     if (adreg_write(0x0, &close_result) != TERM_OK) {
00347         printf("Failed to write BDM register.\r\n");
00348         return false;
00349     }
00350     return true;
00351 }
00352 
00353 bool bdmSyscallFread(void)
00354 {
00355     uint32_t bdm_byte_count, bdm_buffer_address, bdm_file_handle = NULL;
00356     if (adreg_read(&bdm_file_handle, 0x1) != TERM_OK) {
00357         printf("Failed to read BDM register.\r\n");
00358         return false;
00359     }
00360     if (adreg_read(&bdm_byte_count, 0x2) != TERM_OK) {
00361         printf("Failed to read BDM register.\r\n");
00362         return false;
00363     }
00364     if (adreg_read(&bdm_buffer_address, 0x9) != TERM_OK) {
00365         printf("Failed to read BDM register.\r\n");
00366         return false;
00367     }
00368     uint32_t bytes_read = fread(&file_buffer[0],1,bdm_byte_count,fp);
00369     for (uint32_t byte_count = 0; byte_count < bytes_read; byte_count++) {
00370         if (byte_count == 0x0) {
00371             if(memwrite_byte(&bdm_buffer_address, file_buffer[byte_count]) != TERM_OK) return false;
00372         } else {
00373             if(memfill_byte(file_buffer[byte_count]) != TERM_OK) return false;
00374         }
00375     }
00376     if (adreg_write(0x0, &bytes_read) != TERM_OK) {
00377         printf("Failed to write BDM register.\r\n");
00378         return false;
00379     }
00380     return true;
00381 }
00382 
00383 bool bdmSyscallFwrite(void)
00384 {
00385     printf("BDM FWRITE Syscall not supported.\r\n");
00386     return false;
00387 }
00388 
00389 bool bdmSyscallFtell(void)
00390 {
00391     printf("BDM FTELL Syscall not supported.\r\n");
00392     return false;
00393 }
00394 
00395 bool bdmSyscallFseek(void)
00396 {
00397     uint32_t bdm_byte_offset, bdm_file_origin, bdm_file_handle = NULL;
00398     if (adreg_read(&bdm_file_handle, 0x1) != TERM_OK) {
00399         printf("Failed to read BDM register.\r\n");
00400         return false;
00401     }
00402     if (adreg_read(&bdm_byte_offset, 0x2) != TERM_OK) {
00403         printf("Failed to read BDM register.\r\n");
00404         return false;
00405     }
00406     if (adreg_read(&bdm_file_origin, 0x3) != TERM_OK) {
00407         printf("Failed to read BDM register.\r\n");
00408         return false;
00409     }
00410     uint32_t origin;
00411     switch (bdm_file_origin) {
00412         case 0x2:
00413             origin = SEEK_END;
00414             break;
00415         case 0x1:
00416             origin = SEEK_CUR;
00417             break;
00418         case 0x0:
00419         default:
00420             origin = SEEK_SET;
00421             break;
00422     }
00423     uint32_t fseek_result = fseek ( fp ,bdm_byte_offset ,origin );
00424     if (adreg_write(0x0, &fseek_result) != TERM_OK) {
00425         printf("Failed to write BDM register.\r\n");
00426         return false;
00427     }
00428     return true;
00429 }
00430 
00431 bool bdmSyscallFgets(void)
00432 {
00433     printf("BDM FGETS Syscall not supported.\r\n");
00434     return false;
00435 }
00436 
00437 bool bdmSyscallFputs(void)
00438 {
00439     printf("BDM FPUTS Syscall not supported.\r\n");
00440     return false;
00441 }
00442 
00443 bool bdmSyscallEval(void)
00444 {
00445     printf("BDM EVAL Syscall not supported.\r\n");
00446     return false;
00447 }
00448 
00449 bool bdmSyscallFreadsrec(void)
00450 {
00451     printf("BDM FREADSREC Syscall not supported.\r\n");
00452     return false;
00453 }