/// <summary> /// информация о состоянии смены /// </summary> /// <param name="StageStateString"></param> private static void CashDesk_StageStateReceived(StageProperties StageState) { try { //SystemState.KKTStageOpened = (StageState.CurrentStageState == StageProperties.StageState.Opened); StartPage.SystemState.KKTStageOver24h = (StageState.CurrentStageState == StageProperties.StageState.Over24h); StartPage.SystemState.LastStageClosedDateTime = Convert.ToInt64(StageState.StageClosedDateTime.ToString("yyyyMMddHHmmss")); StartPage.SystemState.LastStageClosedDateTimeStr = StageState.StageClosedDateTime.ToString("dd.MM.yyyy HH:mm:ss"); if (StartPage.CurrentState != StartPage.States.Init && StartPage.CurrentState != StartPage.States.OutOfService && StartPage.CurrentState != StartPage.States.ServiceMode && StartPage.SystemState.KKTStageOver24h) { StartPage.CurrentState = StartPage.States.OutOfService; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed MDB.DisableCashDevicesAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed StartPage.AddItemToLogBox("Длительность смены превысила 24ч, устройство переведено в режим \"Не обслуживает\""); } } catch { } }
/// <summary> /// Второй этап запуска - стартуем асинхронные задачи /// </summary> /// <returns></returns> private void RunAfterInit() { if (CurrentDeviceSettings.UseKKT) { CashDeskHelper.CashDesk_Init(); } MDB.ConnectMDBSerialPort(CashDeskDeviceID); I2c_Init(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed ServiceTasks.UpdateWaterCounter(0); ServiceTasks.UpdateCashCounter(0, 0, 0, 0); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed AddItemToLogBox("Управляющее устройство успешно инициализировано, продолжаем..."); int initdelaymillisec = 10000; //подождем немного, винде нужно время, чтобы выделить память, отсвопиться своим гавном //на SD-карту и успокоиться. while (initdelaymillisec > 0) { AddItemToLogBox("Ожидание запуска задач " + (initdelaymillisec / 1000).ToString() + "с..."); int count = 0; while (count < 100) { Task.Delay(100).Wait(); count++; } initdelaymillisec -= 10000; } //Task.Run(CCC, GlobalCancellationTokenSource.Token); ServiceTasks.StartAll(); AddItemToLogBox("Задачи запущены"); Task.Run(MDBHelper.Init_MDB); }
/// <summary> /// Критическая ошибка устройств приема наличных /// </summary> /// <param name="ErrorMessage"></param> private static void CashDevices_MDBError(string ErrorMessage) { if ((StartPage.CurrentState == StartPage.States.ReadyToServe) || (StartPage.CurrentState == StartPage.States.ReadyToDispenseWater) || (StartPage.CurrentState == StartPage.States.DispenseChange)) { StartPage.CurrentState = StartPage.States.OutOfService; MDB.MDBInitStep = 6; MDB.DisableCashDevices(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed StartPage.AddItemToLogBox("Устройства приема наличных принудительно отключены из-за ошибки."); } }
/// <summary> /// MDB устройства включены /// </summary> private static void CashDevices_MDBStarted() { Task.Run(() => { StartPage.UpdateProgress(10); StartPage.UpdateStartLEDs(StartPage.StartPageInstance.MDBLED, Colors.Green); StartPage.AddItemToLogBox("Найден адаптер MDB-RS232"); int count = 0; while (count < 10) { Task.Delay(100).Wait(); count++; } MDB.MDBInitStep = 1; MDB.ResetCashDevices(); }); }
/// <summary> /// Прибавляет 50мл к счетчику отгруженной водички /// </summary> /// <returns></returns> public static void WaterCounterTicked() { if (StartPage.CurrentState == StartPage.States.ReadyToDispenseWater || StartPage.CurrentState == StartPage.States.ServiceMode) { watercountertickerSemaphore.Wait(); if (!(StartPage.CurrentState == StartPage.States.ReadyToDispenseWater || StartPage.CurrentState == StartPage.States.ServiceMode)) { watercountertickerSemaphore.Release(); return; } StartPage.WaterFlowPulseCounter++; if (StartPage.WaterFlowPulseCounter >= 17)//50ml dispensed { StartPage.WaterFlowPulseCounter = 0; if (StartPage.CurrentState == StartPage.States.ReadyToDispenseWater) { StartPage.UserDeposit -= Math.Round(StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE * 0.0005, 2); StartPage.CurrentSaleSession.Quantity += 0.05; if (Math.Round(StartPage.CurrentSaleSession.UserCash, 2) <= Math.Round(StartPage.CurrentSaleSession.Quantity * StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE * 0.01, 2)) { StartPage.CurrentState = StartPage.States.DispenseChange; StartPage.WaterValvePin.Write(GpioPinValue.High); StartPage.PumpPin.Write(GpioPinValue.High); StartPage.StartLEDPin.Write(GpioPinValue.High); StartPage.StopLEDPin.Write(GpioPinValue.High); StartPage.EndLEDPin.Write(GpioPinValue.High); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed MDB.DisableCashDevicesAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(ChangePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } } } watercountertickerSemaphore.Release(); } }
/// <summary> /// MDB устройства включены /// </summary> private static void CashDevices_MDBStarted() { Task.Run(() => { StartPage.UpdateProgress(15); StartPage.UpdateStartLEDs(StartPage.StartPageInstance.MDBLED, Colors.Green); StartPage.UpdateStartLEDs(StartPage.StartPageInstance.UART0LED, Colors.Green); StartPage.AddItemToLogBox("Найден адаптер MDB-RS232"); int count = 0; while (count < 10) { Task.Delay(100).Wait(); count++; } MDBInitStep = 1; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed MDB.ResetCashDevicesAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }); }
/// <summary> /// Критическая ошибка устройств приема наличных /// </summary> /// <param name="ErrorMessage"></param> private static void CashDevices_MDBError(string ErrorMessage) { if ((StartPage.CurrentState == StartPage.States.ReadyToServe) || (StartPage.CurrentState == StartPage.States.ReadyToDispenseWater) || (StartPage.CurrentState == StartPage.States.DispenseChange)) { ChangePage.ChangeModeSemaphore.Wait(); //надо убедиться, что выдача сдачи так или иначе завершена и сессия продажи закрыта ChangePage.ChangeModeSemaphore.Release(); //удерживать флаг эксклюзивного доступа ни к чему, освобождаем StartPage.CurrentState = StartPage.States.OutOfService; MDBInitStep = 6; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed MDB.DisableCashDevicesAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed StartPage.AddItemToLogBox("Устройства приема наличных принудительно отключены из-за ошибки."); } }
/// <summary> /// произведен сброс купюроприемника /// </summary> private static void CashDevices_MDBBAReseted() { Task.Run(() => { Mutex m2 = new Mutex(true, "MDBDeviceResetHandlerMutex", out bool mutexWasCreated); if (!mutexWasCreated) { try { m2.WaitOne(); } catch (AbandonedMutexException) { } } try { if ((!StartPage.bareset) && (MDB.MDBInitStep == 3 || MDB.MDBInitStep == 4)) { MDB.MDBInitStep++; StartPage.UpdateProgress(5); StartPage.bareset = true; StartPage.UpdateStartLEDs(StartPage.StartPageInstance.MDBBALED, Colors.Green); StartPage.AddItemToLogBox("Купюроприемник готов к работе"); if (StartPage.ccreset) { string oosfilename = ApplicationData.Current.LocalFolder.Path + "\\" + GlobalVars.HardWareID + ".031"; StartPage.CurrentState = StartPage.States.OutOfService; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed StartPage.AddItemToLogBox("Ожидание полной инициализации..."); int count = 0; while (count < 100) { Task.Delay(100).Wait(); count++; } MDB.MDBInitStep = 5; StartPage.AddItemToLogBox("Устройства приема наличных обнаружены и настроены"); } } if ((!StartPage.bainit) && (MDB.MDBInitStep == 1 || MDB.MDBInitStep == 2)) { MDB.MDBInitStep++; StartPage.UpdateProgress(5); StartPage.bainit = true; StartPage.UpdateStartLEDs(StartPage.StartPageInstance.MDBBALED, Colors.Yellow); StartPage.AddItemToLogBox("Купюроприемник инициализирован"); StartPage.UpdateProgress(5); int count = 0; while (count < 20) { Task.Delay(100).Wait(); count++; } MDB.ResetBA(); } } catch (Exception ex) { StartPage.AddItemToLogBox("Ошибка: " + ex.Message); } finally { } m2.ReleaseMutex(); m2.Dispose(); }); }
/// <summary> /// выдаем сдачу пока депозит не станет равен 0 /// </summary> private void DispenseChange() { ChangeModeSemaphore.Wait(); if (StartPage.CurrentState != StartPage.States.DispenseChange) { ChangeModeSemaphore.Release(); return; } #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { dispenselabel.Text = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero).ToString().PadLeft(3, '0'); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed if (StartPage.CurrentDeviceSettings.UseKKT && Math.Round(StartPage.CurrentSaleSession.Quantity, 3) > 0) { try { StartPage.CurrentSaleSession.ReceiptNumber = StartPage.SystemState.KKTReceiptNextNumber; StartPage.CurrentSaleSession.StageNumber = Convert.ToInt16(StartPage.SystemState.KKTStageNumber); StartPage.CurrentSaleSession.TaxSystemInUse = StartPage.CurrentDeviceSettings.TaxSystem; if (Math.Round(StartPage.UserDeposit, 2, MidpointRounding.AwayFromZero) == 0) { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, (((int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)) * 1.00 / StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } else { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, Math.Round(StartPage.CurrentSaleSession.Quantity, 3), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } } catch { } } Task.Delay(15000).Wait(); try { CashDesk.GetCurrentStageParameters(); StartPage.CurrentSaleSession.ActualChangeDispensed = (int)Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero); StartPage.CurrentSaleSession.ChangeActualDiff = StartPage.CurrentSaleSession.ActualChangeDispensed - StartPage.UserDeposit; StartPage.CurrentSaleSession.CompleteSession(); ServiceTasks.UpdateWaterCounter(StartPage.CurrentSaleSession.Quantity); StartPage.UserDeposit = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero); while ((int)StartPage.UserDeposit > 0) { while (MDB.DispenseInProgress || MDB.CheckDispenseResult) { Task.Delay(1000).Wait(); } int _change = (int)StartPage.UserDeposit; if (_change > 127)//не более 127 рублей в одной порции сдачи, ограничение монетоприемника { _change = 127; } MDB.Dispensetimeout = DateTime.Now.AddSeconds(10); MDB.PayoutCoins(_change);//выдаем сдачу монетами StartPage.UserDeposit -= _change; Task.Delay(2000).Wait(); } string oosfilename = ApplicationData.Current.LocalFolder.Path + "\\" + GlobalVars.HardWareID + ".031"; if (File.Exists(oosfilename)) { StartPage.CurrentState = StartPage.States.OutOfService; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed return; } StartPage.CurrentState = StartPage.States.ReadyToServe; MDB.EnableCashDevices(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(MainPage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } catch { } ChangeModeSemaphore.Release(); }
/// <summary> /// Нажата кнопка Сдача /// </summary> /// <param name="sender"></param> /// <param name="args"></param> private void EndButtonPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args) { if (args.Edge == GpioPinEdge.RisingEdge) { try { switch (CurrentState) { case States.ReadyToDispenseWater: { CurrentState = States.DispenseChange; MDB.DisableCashDevices(); WaterValvePin.Write(GpioPinValue.High); PumpPin.Write(GpioPinValue.High); StartLEDPin.Write(GpioPinValue.High); StopLEDPin.Write(GpioPinValue.High); EndLEDPin.Write(GpioPinValue.High); ReadyToStartPage.ChangeWaterValveStatus(false); AddItemToLogBox("Сеанс продажи закончен по инициативе покупателя (нажата кнопка \"Конец\"), остаток " + UserDeposit.ToString("N2") + ", выдаем сдачу в размере " + Math.Round(UserDeposit, MidpointRounding.AwayFromZero).ToString("N2")); AddItemToLogBox("Выдача сдачи"); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame2 = Window.Current.Content as Frame; frame2.Navigate(typeof(ChangePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed while (ChangePage.ChangePageInstance == null) { Task.Delay(100).Wait(); } break; } case States.ServiceMode: { WaterValvePin.Write(GpioPinValue.High); PumpPin.Write(GpioPinValue.High); StartLEDPin.Write(GpioPinValue.High); StopLEDPin.Write(GpioPinValue.High); EndLEDPin.Write(GpioPinValue.High); ReadyToStartPage.ChangeWaterValveStatus(false); string oosfilename = ApplicationData.Current.LocalFolder.Path + "\\" + GlobalVars.HardWareID + ".031"; if (File.Exists(oosfilename)) { CurrentState = States.OutOfService; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed AddItemToLogBox("Временно не обслуживает"); return; } CurrentState = States.ReadyToServe; MDB.EnableCashDevices(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(MainPage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed while (MainPage.MainPageInstance == null) { Task.Delay(100).Wait(); } AddItemToLogBox("Выход из служебного режима по инициативе оператора (нажата кнопка \"Конец\")"); break; } default: { AddItemToLogBox("Кнопка \"Конец\" нажата вне контекста продажи или служебного режима, действие не требуется."); break; } } } catch { } finally { } } }
/// <summary> /// выдаем сдачу пока депозит не станет равен 0 /// </summary> private void DispenseChange() { ChangeModeSemaphore.Wait(); if (StartPage.CurrentState != StartPage.States.DispenseChange) { ChangeModeSemaphore.Release(); return; } #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { dispenselabel.Text = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero).ToString().PadLeft(3, '0'); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed if (StartPage.CurrentDeviceSettings.UseKKT && Math.Round(StartPage.CurrentSaleSession.Quantity, 3) > 0) { try { StartPage.CurrentSaleSession.ReceiptNumber = StartPage.SystemState.KKTReceiptNextNumber; StartPage.CurrentSaleSession.StageNumber = Convert.ToInt16(StartPage.SystemState.KKTStageNumber); StartPage.CurrentSaleSession.TaxSystemInUse = StartPage.CurrentDeviceSettings.TaxSystem; if (Math.Round(StartPage.UserDeposit, 2, MidpointRounding.AwayFromZero) == 0) { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, (((int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)) * 1.00 / StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } else { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, Math.Round(StartPage.CurrentSaleSession.Quantity, 3), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } } catch { } } while (CashDesk.PendingTasks.Count(x => x.Status != CashDesk.KKTTaskStatus.Completed) > 0) { Task.Delay(100).Wait(); } try { CashDesk.GetCurrentStageParameters(); ServiceTasks.UpdateWaterCounter(StartPage.CurrentSaleSession.Quantity); StartPage.UserDeposit = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero); int ExpectedDeposit = (int)StartPage.UserDeposit; while ((int)StartPage.UserDeposit > 0) { while (MDB.DispenseInProgress || MDB.AwaitDispenseResult) { Task.Delay(1000).Wait(); } if (ExpectedDeposit == (int)StartPage.UserDeposit) { ExpectedDeposit = (int)StartPage.UserDeposit - (int)StartPage.UserDeposit & 0x7f; MDB.PayoutCoinsAsync((int)StartPage.UserDeposit & 0x7f).Wait();//выдаем сдачу монетами, не более 127 рублей за раз } else { if ((int)StartPage.UserDeposit > 0) { //это не очень хорошая ситуация, часть сдачи или всю мы не отдали, //либо отдали, но монетоприемник не прислал об этом никакой информации по какой-то причине //в отведенное для этого время (см MDBHelper.CashDevices_MDBChangeDispensed). //Информация об этом будет видна в личном кабинете, в таблице продаж отражается //выданная сдача и разница между расчетным и реальнно выданным значением. //Если монетоприемник пришлет ошибку, автомат перейдет в режим OutOfService автоматически (см MDBHelper.CashDevices_MDBError) //выходим из процедуры выдачи сдачи, не будем разбрасывать зря бабло. break; } } } } catch { } finally { StartPage.CurrentSaleSession.ChangeActualDiff = StartPage.CurrentSaleSession.ActualChangeDispensed - StartPage.CurrentSaleSession.UserCash; //пишем разницу между расчетным и реальнно выданным значением сдачи StartPage.CurrentSaleSession.CompleteSession(); //закрываем продажу string oosfilename = ApplicationData.Current.LocalFolder.Path + "\\" + GlobalVars.HardWareID + ".031"; if (File.Exists(oosfilename)) { StartPage.CurrentState = StartPage.States.OutOfService; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } else { StartPage.CurrentState = StartPage.States.ReadyToServe; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed MDB.EnableCashDevicesAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(MainPage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } ChangeModeSemaphore.Release(); } }