//----------------------------------------------------------------------------- // Copyright 2007 Jonathan Westhues // // This file is part of LDmicro. // // LDmicro is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // LDmicro is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with LDmicro. If not, see . //------ // // Miscellaneous utility functions that don't fit anywhere else. IHEX writing, // verified memory allocator, other junk. //----------------------------------------------------------------------------- #include "linuxUI.h" #include #include #include #include "ldmicro.h" // We should display messages to the user differently if we are running // interactively vs. in batch (command-line) mode. BOOL RunningInBatchMode = FALSE; // Allocate memory on a local heap HANDLE MainHeap; // Running checksum as we build up IHEX records. static int IhexChecksum; // Try to common a bit of stuff between the dialog boxes, since only one // can be open at any time. HWID OkButton; HWID CancelButton; BOOL DialogDone; BOOL DialogCancel; HFONT MyNiceFont; HFONT MyFixedFont; //----------------------------------------------------------------------------- // printf-like debug function, to the Windows debug log. //----------------------------------------------------------------------------- void dbp(char *str, ...) { va_list f; char buf[1024]; va_start(f, str); vsprintf(buf, str, f); OutputDebugString(buf); OutputDebugString("\n"); } //----------------------------------------------------------------------------- // Wrapper for AttachConsole that does nothing running under = 0x500 // BOOL AttachConsoleDynamic(DWORD base) // { // typedef BOOL WINAPI fptr_acd(DWORD base); // fptr_acd *fp; // HMODULE hm = LoadLibrary("kernel32.dll"); // if(!hm) return FALSE; // fp = (fptr_acd *)GetProcAddress(hm, "AttachConsole"); // if(!fp) return FALSE; // return fp(base); // } //----------------------------------------------------------------------------- // For error messages to the user; printf-like, to a message box. //----------------------------------------------------------------------------- void Error(char *str, ...) { va_list f; char buf[1024]; va_start(f, str); vsprintf(buf, str, f); va_end(f); if(RunningInBatchMode) { printf("print batch mode"); /* Only required for windows * AttachConsoleDynamic(ATTACH_PARENT_PROCESS); */ // Indicate that it's an error, plus the output filename printf("compile error ('%s'): \n", CurrentCompileFile); // The error message itself and an extra newline to be safe. printf("%s\n", buf); } else { //HWND h = GetForegroundWindow(); MessageBox(MainWindow, buf, _("LDmicro Error"), MB_OK, MB_ICONERROR); } } //----------------------------------------------------------------------------- // A standard format for showing a message that indicates that a compile // was successful. //----------------------------------------------------------------------------- void CompileSuccessfulMessage(char *str) { if(RunningInBatchMode) { char str[MAX_PATH+100]; printf("compiled okay, wrote '%s'\n", CurrentCompileFile); //AttachConsoleDynamic(ATTACH_PARENT_PROCESS); //HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); //DWORD written; //WriteFile(h, str, strlen(str), &written, NULL); } else { MessageBox(MainWindow, str, _("Compile Successful"), MB_OK, MB_ICONINFORMATION); } } //----------------------------------------------------------------------------- // Check the consistency of the heap on which all the PLC program stuff is // stored. //----------------------------------------------------------------------------- void CheckHeap(char *file, int line) { static unsigned int SkippedCalls; static SDWORD LastCallTime; SDWORD now = GetTickCount(); // It slows us down too much to do the check every time we are called; // but let's still do the check periodically; let's do it every 70 // calls or every 20 ms, whichever is sooner. if(SkippedCalls < 70 && (now - LastCallTime) < 20) { SkippedCalls++; return; } SkippedCalls = 0; LastCallTime = now; /*if(!HeapValidate(MainHeap, 0, NULL)) { dbp("file %s line %d", file, line); Error("Noticed memory corruption at file '%s' line %d.", file, line); oops(); }*/ } //----------------------------------------------------------------------------- // Like malloc/free, but memsets memory allocated to all zeros. Also TODO some // checking and something sensible if it fails. //----------------------------------------------------------------------------- void *CheckMalloc(size_t n) { ok(); void *p = HeapAlloc(MainHeap, HEAP_ZERO_MEMORY, n); return p; } void CheckFree(void *p) { ok(); HeapFree(MainHeap, 0, p); } //----------------------------------------------------------------------------- // Clear the checksum and write the : that starts an IHEX record. //----------------------------------------------------------------------------- void StartIhex(FILE *f) { fprintf(f, ":"); IhexChecksum = 0; } //----------------------------------------------------------------------------- // Write an octet in hex format to the given stream, and update the checksum // for the IHEX file. //----------------------------------------------------------------------------- void WriteIhex(FILE *f, BYTE b) { fprintf(f, "%02X", b); IhexChecksum += b; } //----------------------------------------------------------------------------- // Write the finished checksum to the IHEX file from the running sum // calculated by WriteIhex. //----------------------------------------------------------------------------- void FinishIhex(FILE *f) { IhexChecksum = ~IhexChecksum + 1; IhexChecksum = IhexChecksum & 0xff; fprintf(f, "%02X\n", IhexChecksum); } //----------------------------------------------------------------------------- // Create a window with a given client area. //----------------------------------------------------------------------------- QDialog* CreateWindowClient(char *windowName, int x, int y, int width, int height, HWND parent) { QDialog* h = new QDialog(parent); h->resize(width, height); h->setWindowTitle(windowName); return h; } //----------------------------------------------------------------------------- // Set the font of a control to a pretty proportional font (typ. Tahoma). //----------------------------------------------------------------------------- void NiceFont(HWID h) { QFont qtfont = h->font(); qtfont.setFamily(MyNiceFont->lpszFace); qtfont.setPixelSize(MyNiceFont->nHeight - 3); qtfont.setFixedPitch(TRUE); qtfont.setStyle( MyNiceFont->fdwItalic ? QFont::StyleItalic : QFont::StyleNormal); qtfont.setWeight( MyNiceFont->fnWeight == FW_BOLD ? QFont::Bold : QFont::Normal); h->setFont(qtfont); // SendMessage(h, WM_SETFONT, (WPARAM)MyNiceFont, TRUE); } //----------------------------------------------------------------------------- // Set the font of a control to a pretty fixed-width font (typ. Lucida // Console). //----------------------------------------------------------------------------- void FixedFont(HWID h) { QFont qtfont = h->font(); qtfont.setFamily(MyFixedFont->lpszFace); qtfont.setPixelSize(MyFixedFont->nHeight - 3); qtfont.setFixedPitch(TRUE); qtfont.setStyle( MyFixedFont->fdwItalic ? QFont::StyleItalic : QFont::StyleNormal); qtfont.setWeight( MyFixedFont->fnWeight == FW_BOLD ? QFont::Bold : QFont::Normal); h->setFont(qtfont); // SendMessage(h, WM_SETFONT, (WPARAM)MyFixedFont, TRUE); } void SetFont(HWID h, HFONT f) { QFont qtfont = h->font(); qtfont.setFamily(f->lpszFace); qtfont.setPixelSize(f->nHeight - 3); qtfont.setFixedPitch(TRUE); qtfont.setStyle(f->fdwItalic ? QFont::StyleItalic : QFont::StyleNormal); qtfont.setWeight(f->fnWeight == FW_BOLD ? QFont::Bold : QFont::Normal); h->setFont(qtfont); } //----------------------------------------------------------------------------- // Create our dialog box class, used for most of the popup dialogs. //----------------------------------------------------------------------------- void MakeDialogBoxClass(void) { MyNiceFont = CreateFont(16, 0, 0, FW_REGULAR, FALSE, "Tahoma"); MyFixedFont = CreateFont(14, 0, 0, FW_REGULAR, FALSE, "Lucida Console"); } //----------------------------------------------------------------------------- // Map an I/O type to a string describing it. Used both in the on-screen // list and when we write a text file to describe it. //----------------------------------------------------------------------------- char *IoTypeToString(int ioType) { switch(ioType) { case IO_TYPE_DIG_INPUT: return _("digital in"); case IO_TYPE_DIG_OUTPUT: return _("digital out"); case IO_TYPE_INTERNAL_RELAY: return _("int. relay"); case IO_TYPE_UART_TX: return _("UART tx"); case IO_TYPE_UART_RX: return _("UART rx"); case IO_TYPE_PWM_OUTPUT: return _("PWM out"); case IO_TYPE_TON: return _("turn-on delay"); case IO_TYPE_TOF: return _("turn-off delay"); case IO_TYPE_RTO: return _("retentive timer"); case IO_TYPE_COUNTER: return _("counter"); case IO_TYPE_GENERAL: return _("general var"); case IO_TYPE_READ_ADC: return _("adc input"); default: return _(""); } } //----------------------------------------------------------------------------- // Get a pin number for a given I/O; for digital ins and outs and analog ins, // this is easy, but for PWM and UART this is forced (by what peripherals // are available) so we look at the characteristics of the MCU that is in // use. //----------------------------------------------------------------------------- void PinNumberForIo(char *dest, PlcProgramSingleIo *io) { if(!dest) return; if(!io) { strcpy(dest, ""); return; } int type = io->type; if(type == IO_TYPE_DIG_INPUT || type == IO_TYPE_DIG_OUTPUT || type == IO_TYPE_READ_ADC) { int pin = io->pin; if(pin == NO_PIN_ASSIGNED) { strcpy(dest, _("(not assigned)")); } else { sprintf(dest, "%d", pin); } } else if(type == IO_TYPE_UART_TX && Prog.mcu) { if(Prog.mcu->uartNeeds.txPin == 0) { strcpy(dest, _("")); } else { sprintf(dest, "%d", Prog.mcu->uartNeeds.txPin); } } else if(type == IO_TYPE_UART_RX && Prog.mcu) { if(Prog.mcu->uartNeeds.rxPin == 0) { strcpy(dest, _("")); } else { sprintf(dest, "%d", Prog.mcu->uartNeeds.rxPin); } } else if(type == IO_TYPE_PWM_OUTPUT && Prog.mcu) { if(Prog.mcu->pwmNeedsPin == 0) { strcpy(dest, _("")); } else { sprintf(dest, "%d", Prog.mcu->pwmNeedsPin); } } else { strcpy(dest, ""); } }