//----------------------------------------------------------------------------- // 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" using namespace std; // 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; //riteFile(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. //----------------------------------------------------------------------------- HWID CreateWindowClient(GtkWindowType wType, GdkWindowTypeHint wthint, char *windowName, int x, int y, int width, int height, HWND parent) { HWID h = gtk_window_new(wType); gtk_window_set_title(GTK_WINDOW(h), windowName); gtk_window_resize (GTK_WINDOW(h), width, height); gtk_window_move(GTK_WINDOW(h), x, y); gtk_window_set_type_hint (GTK_WINDOW(h), wthint); // HWND h = CreateWindowEx(exStyle, className, windowName, style, x, y, // width, height, parent, menu, instance, param); // RECT r; // GetClientRect(h, &r); // width = width - (r.right - width); // height = height - (r.bottom - height); // SetWindowPos(h, HWND_TOP, x, y, width, height, 0); return h; } //----------------------------------------------------------------------------- // Window proc for the dialog boxes. This Ok/Cancel stuff is common to a lot // of places, and there are no other callbacks from the children. //----------------------------------------------------------------------------- // static LRESULT CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, // LPARAM lParam) // { // switch (msg) { // case WM_NOTIFY: // break; // case WM_COMMAND: { // HWND h = (HWND)lParam; // if(h == OkButton && wParam == BN_CLICKED) { // DialogDone = TRUE; // } else if(h == CancelButton && wParam == BN_CLICKED) { // DialogDone = TRUE; // DialogCancel = TRUE; // } // break; // } // case WM_CLOSE: // case WM_DESTROY: // DialogDone = TRUE; // DialogCancel = TRUE; // break; // default: // return DefWindowProc(hwnd, msg, wParam, lParam); // } // return 1; // } //----------------------------------------------------------------------------- // Set the font of a control to a pretty proportional font (typ. Tahoma). //----------------------------------------------------------------------------- void NiceFont(HWID h) { GtkCssProvider *provider = gtk_css_provider_new (); char *cssdata = new char[strlen(MyNiceFont->lpszFace) + 26]; int fontSize = 10; sprintf(cssdata, "textview { font: %ipx %s; }", fontSize, MyNiceFont->lpszFace); gtk_css_provider_load_from_data (provider, cssdata, -1, NULL); delete cssdata; gtk_style_context_add_provider (gtk_widget_get_style_context(h), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); // 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) { GtkCssProvider *provider = gtk_css_provider_new (); char *cssdata = new char[strlen(MyFixedFont->lpszFace) + 26]; int fontSize = 10; sprintf(cssdata, "textview { font: %ipx %s; }", fontSize, MyFixedFont->lpszFace); gtk_css_provider_load_from_data (provider, cssdata, -1, NULL); delete cssdata; gtk_style_context_add_provider (gtk_widget_get_style_context(h), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); // SendMessage(h, WM_SETFONT, (WPARAM)MyFixedFont, TRUE); } //----------------------------------------------------------------------------- // Create our dialog box class, used for most of the popup dialogs. //----------------------------------------------------------------------------- void MakeDialogBoxClass(void) { // WNDCLASSEX wc; // memset(&wc, 0, sizeof(wc)); // wc.cbSize = sizeof(wc); // wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC | // CS_DBLCLKS; // wc.lpfnWndProc = (WNDPROC)DialogProc; // wc.hInstance = Instance; // wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; // wc.lpszClassName = "LDmicroDialog"; // wc.lpszMenuName = NULL; // wc.hCursor = LoadCursor(NULL, IDC_ARROW); // wc.hIcon = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000), // IMAGE_ICON, 32, 32, 0); // wc.hIconSm = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000), // IMAGE_ICON, 16, 16, 0); // RegisterClassEx(&wc); MyNiceFont = CreateFont(16, 0, 0, FW_REGULAR, FALSE, "Tahoma"); // if(!MyNiceFont) // MyNiceFont = (HFONT)GetStockObject(SYSTEM_FONT); MyFixedFont = CreateFont(14, 0, 0, FW_REGULAR, FALSE, "Lucida Console"); // if(!MyFixedFont) // MyFixedFont = (HFONT)GetStockObject(SYSTEM_FONT); } //----------------------------------------------------------------------------- // 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, ""); } }