// Queue a character for transmission void jshTransmit(IOEventFlags device, unsigned char data) { #ifndef LINUX #ifdef USB if (device==EV_USBSERIAL && !jshIsUSBSERIALConnected()) { jshTransmitClearDevice(EV_USBSERIAL); // clear out stuff already waiting return; } #endif if (device==EV_NONE) return; unsigned char txHeadNext = (txHead+1)&TXBUFFERMASK; if (txHeadNext==txTail) { jsiSetBusy(BUSY_TRANSMIT, true); while (txHeadNext==txTail) { // wait for send to finish as buffer is about to overflow #ifdef USB // just in case USB was unplugged while we were waiting! if (!jshIsUSBSERIALConnected()) jshTransmitClearDevice(EV_USBSERIAL); #endif } jsiSetBusy(BUSY_TRANSMIT, false); } txBuffer[txHead].flags = device; txBuffer[txHead].data = (char)data; txHead = txHeadNext; jshUSARTKick(device); // set up interrupts if required #else // if PC, just put to stdout if (device==DEFAULT_CONSOLE_DEVICE) { fputc(data, stdout); fflush(stdout); } #endif }
/** * Queue a character for transmission. */ void jshTransmit( IOEventFlags device, //!< The device to be used for transmission. unsigned char data //!< The character to transmit. ) { if (device==EV_LOOPBACKA || device==EV_LOOPBACKB) { jshPushIOCharEvent(device==EV_LOOPBACKB ? EV_LOOPBACKA : EV_LOOPBACKB, (char)data); return; } #ifndef LINUX #ifdef USB if (device==EV_USBSERIAL && !jshIsUSBSERIALConnected()) { jshTransmitClearDevice(EV_USBSERIAL); // clear out stuff already waiting return; } #endif #else // if PC, just put to stdout if (device==DEFAULT_CONSOLE_DEVICE) { fputc(data, stdout); fflush(stdout); return; } #endif // If the device is EV_NONE then there is nowhere to send the data. if (device==EV_NONE) return; // The txHead global points to the current item in the txBuffer. Since we are adding a new // character, we increment the head pointer. If it has caught up with the tail, then that means // we have filled the array backing the list. What we do next is to wait for space to free up. unsigned char txHeadNext = (unsigned char)((txHead+1)&TXBUFFERMASK); if (txHeadNext==txTail) { jsiSetBusy(BUSY_TRANSMIT, true); bool wasConsoleLimbo = device==EV_LIMBO && jsiGetConsoleDevice()==EV_LIMBO; while (txHeadNext==txTail) { // wait for send to finish as buffer is about to overflow #ifdef USB // just in case USB was unplugged while we were waiting! if (!jshIsUSBSERIALConnected()) jshTransmitClearDevice(EV_USBSERIAL); #endif } if (wasConsoleLimbo && jsiGetConsoleDevice()!=EV_LIMBO) { /* It was 'Limbo', but now it's not - see jsiOneSecondAfterStartup. Basically we must have printed a bunch of stuff to LIMBO and blocked with our output buffer full. But then jsiOneSecondAfterStartup switches to the right console device and swaps everything we wrote over to that device too. Only we're now here, still writing to the old device when really we should be writing to the new one. */ device = jsiGetConsoleDevice(); } jsiSetBusy(BUSY_TRANSMIT, false); } // Save the device and data for the new character to be transmitted. txBuffer[txHead].flags = device; txBuffer[txHead].data = data; txHead = txHeadNext; jshUSARTKick(device); // set up interrupts if required }
int main(void) { initHardware(); int flashy = 0; BootloaderState state = BLS_UNDEFINED; char currentCommand = 0; while (1) { if (!jshIsUSBSERIALConnected()) { jshPinOutput(LED2_PININDEX, 0); // reset, led off } else { int f = (flashy>>9) & 0x7F; if (f&0x40) f=128-f; jshPinOutput(LED3_PININDEX, ((flashy++)&0xFF)<f); // flash led int d = getc(); if (d>=0) { // if we have data if (state==BLS_EXPECT_DATA) { } else if (state==BLS_INITED) { currentCommand = d; state = BLS_COMMAND_FIRST_BYTE; } else if (state==BLS_COMMAND_FIRST_BYTE) { if (currentCommand == d^0xFF) { unsigned int addr,i; char chksum, buffer[256]; unsigned int nBytesMinusOne, nPages; // confirmed switch (currentCommand) { case CMD_GET: // get bootloader info putc(ACK); putc(5); // 6 bytes // now report what we support putc(BOOTLOADER_MAJOR_VERSION<<4 | BOOTLOADER_MINOR_VERSION); // Bootloader version // list supported commands putc(CMD_GET); putc(CMD_GET_ID); putc(CMD_READ); putc(CMD_WRITE); putc(CMD_EXTERASE); // erase putc(ACK); // last byte break; case CMD_GET_ID: // get chip ID putc(ACK); putc(1); // 2 bytes // now report what we support putc(0x04); // 0x30 F1 XL density // 0x14 F1 high density putc(0x30); // TODO: really? putc(ACK); // last byte break; case CMD_READ: // read memory putc(ACK); addr = getc_blocking() << 24; addr |= getc_blocking() << 16; addr |= getc_blocking() << 8; addr |= getc_blocking(); chksum = getc_blocking(); // TODO: check checksum putc(ACK); setLEDs(2); // green = wait for data nBytesMinusOne = getc_blocking(); chksum = getc_blocking(); // TODO: check checksum putc(ACK); for (i=0;i<=nBytesMinusOne;i++) putc(((unsigned char*)addr)[i]); setLEDs(0); // off break; case CMD_WRITE: // write memory putc(ACK); addr = getc_blocking() << 24; addr |= getc_blocking() << 16; addr |= getc_blocking() << 8; addr |= getc_blocking(); chksum = getc_blocking(); // TODO: check checksum and address&3==0 putc(ACK); setLEDs(2); // green = wait for data nBytesMinusOne = getc_blocking(); for (i=0;i<=nBytesMinusOne;i++) buffer[i] = getc_blocking(); chksum = getc_blocking(); setLEDs(1); // red = write // TODO: check checksum and (nBytesMinusOne+1)&3==0 FLASH_UnlockBank1(); for (i=0;i<=nBytesMinusOne;i+=4) { unsigned int realaddr = addr+i; if (realaddr >= (FLASH_START+BOOTLOADER_SIZE)) // protect bootloader FLASH_ProgramWord(realaddr, *(unsigned int*)&buffer[i]); } FLASH_LockBank1(); setLEDs(0); // off putc(ACK); // TODO - could speed up writes by ACKing beforehand if we have space break; case CMD_EXTERASE: // erase memory putc(ACK); nPages = getc_blocking() << 8; nPages |= getc_blocking(); chksum = getc_blocking(); // TODO: check checksum if (nPages == 0xFFFF) { // all pages (except us!) setLEDs(1); // red = write FLASH_UnlockBank1(); for (i=BOOTLOADER_SIZE;i<FLASH_TOTAL;i+=FLASH_PAGE_SIZE) FLASH_ErasePage((uint32_t)(FLASH_START + i)); FLASH_LockBank1(); setLEDs(0); // off putc(ACK); } else { putc(NACK); // not implemented } break; default: // unknown command putc(NACK); break; } } else { // not correct putc(NACK); } state = BLS_INITED; } else { switch (d) { case 0x7F: // initialisation byte putc(state == BLS_UNDEFINED ? ACK : NACK); state = BLS_INITED; break; } } } } } }