📄 ldmicro.cpp
字号:
//-----------------------------------------------------------------------------
// 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 <http://www.gnu.org/licenses/>.
//------
//
// A ladder logic compiler for 8 bit micros: user draws a ladder diagram,
// with an appropriately constrained `schematic editor,' and then we can
// simulated it under Windows or generate PIC/AVR code that performs the
// requested operations. This files contains the program entry point, plus
// most of the UI logic relating to the main window.
// Jonathan Westhues, Oct 2004
//-----------------------------------------------------------------------------
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <stdlib.h>
#include "ldmicro.h"
#include "freeze.h"
#include "mcutable.h"
HINSTANCE Instance;
HWND MainWindow;
HDC Hdc;
// parameters used to capture the mouse when implementing our totally non-
// general splitter control
static HHOOK MouseHookHandle;
static int MouseY;
// For the open/save dialog boxes
#define LDMICRO_PATTERN "LDmicro Ladder Logic Programs (*.ld)\0*.ld\0" \
"All files\0*\0\0"
char CurrentSaveFile[MAX_PATH];
static BOOL ProgramChangedNotSaved = FALSE;
#define HEX_PATTERN "Intel Hex Files (*.hex)\0*.hex\0All files\0*\0\0"
#define C_PATTERN "C Source Files (*.c)\0*.c\0All Files\0*\0\0"
#define INTERPRETED_PATTERN \
"Interpretable Byte Code Files (*.int)\0*.int\0All Files\0*\0\0"
char CurrentCompileFile[MAX_PATH];
#define TXT_PATTERN "Text Files (*.txt)\0*.txt\0All files\0*\0\0"
// Everything relating to the PLC's program, I/O configuration, processor
// choice, and so on--basically everything that would be saved in the
// project file.
PlcProgram Prog;
//-----------------------------------------------------------------------------
// Get a filename with a common dialog box and then save the program to that
// file and then set our default filename to that.
//-----------------------------------------------------------------------------
static BOOL SaveAsDialog(void)
{
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance;
ofn.lpstrFilter = LDMICRO_PATTERN;
ofn.lpstrDefExt = "ld";
ofn.lpstrFile = CurrentSaveFile;
ofn.nMaxFile = sizeof(CurrentSaveFile);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
if(!GetSaveFileName(&ofn))
return FALSE;
if(!SaveProjectToFile(CurrentSaveFile)) {
Error(_("Couldn't write to '%s'."), CurrentSaveFile);
return FALSE;
} else {
ProgramChangedNotSaved = FALSE;
return TRUE;
}
}
//-----------------------------------------------------------------------------
// Get a filename with a common dialog box and then export the program as
// an ASCII art drawing.
//-----------------------------------------------------------------------------
static void ExportDialog(void)
{
char exportFile[MAX_PATH];
OPENFILENAME ofn;
exportFile[0] = '\0';
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance;
ofn.lpstrFilter = TXT_PATTERN;
ofn.lpstrFile = exportFile;
ofn.lpstrTitle = _("Export As Text");
ofn.nMaxFile = sizeof(exportFile);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
if(!GetSaveFileName(&ofn))
return;
ExportDrawingAsText(exportFile);
}
//-----------------------------------------------------------------------------
// If we already have a filename, save the program to that. Otherwise same
// as Save As. Returns TRUE if it worked, else returns FALSE.
//-----------------------------------------------------------------------------
static BOOL SaveProgram(void)
{
if(strlen(CurrentSaveFile)) {
if(!SaveProjectToFile(CurrentSaveFile)) {
Error(_("Couldn't write to '%s'."), CurrentSaveFile);
return FALSE;
} else {
ProgramChangedNotSaved = FALSE;
return TRUE;
}
} else {
return SaveAsDialog();
}
}
//-----------------------------------------------------------------------------
// Compile the program to a hex file for the target micro. Get the output
// file name if necessary, then call the micro-specific compile routines.
//-----------------------------------------------------------------------------
static void CompileProgram(BOOL compileAs)
{
if(compileAs || strlen(CurrentCompileFile)==0) {
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance;
ofn.lpstrTitle = _("Compile To");
if(Prog.mcu && Prog.mcu->whichIsa == ISA_ANSIC) {
ofn.lpstrFilter = C_PATTERN;
ofn.lpstrDefExt = "c";
} else if(Prog.mcu && Prog.mcu->whichIsa == ISA_INTERPRETED) {
ofn.lpstrFilter = INTERPRETED_PATTERN;
ofn.lpstrDefExt = "int";
} else {
ofn.lpstrFilter = HEX_PATTERN;
ofn.lpstrDefExt = "hex";
}
ofn.lpstrFile = CurrentCompileFile;
ofn.nMaxFile = sizeof(CurrentCompileFile);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
if(!GetSaveFileName(&ofn))
return;
// hex output filename is stored in the .ld file
ProgramChangedNotSaved = TRUE;
}
if(!GenerateIntermediateCode()) return;
if(Prog.mcu == NULL) {
Error(_("Must choose a target microcontroller before compiling."));
return;
}
if(UartFunctionUsed() && Prog.mcu->uartNeeds.rxPin == 0) {
Error(_("UART function used but not supported for this micro."));
return;
}
if(PwmFunctionUsed() && Prog.mcu->pwmNeedsPin == 0) {
Error(_("PWM function used but not supported for this micro."));
return;
}
switch(Prog.mcu->whichIsa) {
case ISA_AVR: CompileAvr(CurrentCompileFile); break;
case ISA_PIC16: CompilePic16(CurrentCompileFile); break;
case ISA_ANSIC: CompileAnsiC(CurrentCompileFile); break;
case ISA_INTERPRETED: CompileInterpreted(CurrentCompileFile); break;
default: oops();
}
// IntDumpListing("t.pl");
}
//-----------------------------------------------------------------------------
// If the program has been modified then give the user the option to save it
// or to cancel the operation they are performing. Return TRUE if they want
// to cancel.
//-----------------------------------------------------------------------------
BOOL CheckSaveUserCancels(void)
{
if(!ProgramChangedNotSaved) {
// no problem
return FALSE;
}
int r = MessageBox(MainWindow,
_("The program has changed since it was last saved.\r\n\r\n"
"Do you want to save the changes?"), "LDmicro",
MB_YESNOCANCEL | MB_ICONWARNING);
switch(r) {
case IDYES:
if(SaveProgram())
return FALSE;
else
return TRUE;
case IDNO:
return FALSE;
case IDCANCEL:
return TRUE;
default:
oops();
}
}
//-----------------------------------------------------------------------------
// Load a new program from a file. If it succeeds then set our default filename
// to that, else we end up with an empty file then.
//-----------------------------------------------------------------------------
static void OpenDialog(void)
{
OPENFILENAME ofn;
char tempSaveFile[MAX_PATH] = "";
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance;
ofn.lpstrFilter = LDMICRO_PATTERN;
ofn.lpstrDefExt = "ld";
ofn.lpstrFile = tempSaveFile;
ofn.nMaxFile = sizeof(tempSaveFile);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
if(!GetOpenFileName(&ofn))
return;
if(!LoadProjectFromFile(tempSaveFile)) {
Error(_("Couldn't open '%s'."), tempSaveFile);
CurrentSaveFile[0] = '\0';
} else {
ProgramChangedNotSaved = FALSE;
strcpy(CurrentSaveFile, tempSaveFile);
UndoFlush();
}
GenerateIoListDontLoseSelection();
RefreshScrollbars();
UpdateMainWindowTitleBar();
}
//-----------------------------------------------------------------------------
// Housekeeping required when the program changes: mark the program as
// changed so that we ask if user wants to save before exiting, and update
// the I/O list.
//-----------------------------------------------------------------------------
void ProgramChanged(void)
{
ProgramChangedNotSaved = TRUE;
GenerateIoListDontLoseSelection();
RefreshScrollbars();
}
#define CHANGING_PROGRAM(x) { \
UndoRemember(); \
x; \
ProgramChanged(); \
}
//-----------------------------------------------------------------------------
// Hook that we install when the user starts dragging the `splitter,' in case
// they drag it out of the narrow area of the drawn splitter bar. Resize
// the listview in response to mouse move, and unhook ourselves when they
// release the mouse button.
//-----------------------------------------------------------------------------
static LRESULT CALLBACK MouseHook(int code, WPARAM wParam, LPARAM lParam)
{
switch(code) {
case HC_ACTION: {
MSLLHOOKSTRUCT *mhs = (MSLLHOOKSTRUCT *)lParam;
switch(wParam) {
case WM_MOUSEMOVE: {
int dy = MouseY - mhs->pt.y;
IoListHeight += dy;
if(IoListHeight < 50) IoListHeight = 50;
MouseY = mhs->pt.y;
MainWindowResized();
break;
}
case WM_LBUTTONUP:
UnhookWindowsHookEx(MouseHookHandle);
break;
}
break;
}
}
return CallNextHookEx(MouseHookHandle, code, wParam, lParam);
}
//-----------------------------------------------------------------------------
// Handle a selection from the menu bar of the main window.
//-----------------------------------------------------------------------------
static void ProcessMenu(int code)
{
if(code >= MNU_PROCESSOR_0 && code < MNU_PROCESSOR_0+NUM_SUPPORTED_MCUS) {
strcpy(CurrentCompileFile, "");
Prog.mcu = &SupportedMcus[code - MNU_PROCESSOR_0];
RefreshControlsToSettings();
return;
}
if(code == MNU_PROCESSOR_0+NUM_SUPPORTED_MCUS) {
Prog.mcu = NULL;
strcpy(CurrentCompileFile, "");
RefreshControlsToSettings();
return;
}
switch(code) {
case MNU_NEW:
if(CheckSaveUserCancels()) break;
NewProgram();
strcpy(CurrentSaveFile, "");
strcpy(CurrentCompileFile, "");
GenerateIoListDontLoseSelection();
RefreshScrollbars();
UpdateMainWindowTitleBar();
break;
case MNU_OPEN:
if(CheckSaveUserCancels()) break;
OpenDialog();
break;
case MNU_SAVE:
SaveProgram();
UpdateMainWindowTitleBar();
break;
case MNU_SAVE_AS:
SaveAsDialog();
UpdateMainWindowTitleBar();
break;
case MNU_EXPORT:
ExportDialog();
break;
case MNU_EXIT:
if(CheckSaveUserCancels()) break;
PostQuitMessage(0);
break;
case MNU_INSERT_COMMENT:
CHANGING_PROGRAM(AddComment(_("--add comment here--")));
break;
case MNU_INSERT_CONTACTS:
CHANGING_PROGRAM(AddContact());
break;
case MNU_INSERT_COIL:
CHANGING_PROGRAM(AddCoil());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -