neotron_common_bios/
types.rs

1//! # Types
2//!
3//! Contains types used in the Neotron API.
4//!
5//! Note that all types in this file that are exported in the `Api` structure
6//! *must* be `#[repr(C)]` and ABI stable.
7
8// Copyright (C) The Neotron Developers, 2019-2022
9//
10// This program is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// at your option) any later version.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program.  If not, see <https://www.gnu.org/licenses/>.
22
23// ============================================================================
24// Imports
25// ============================================================================
26
27use crate::make_ffi_enum;
28
29// ============================================================================
30// Constants
31// ============================================================================
32
33// None
34
35// ============================================================================
36// Types
37// ============================================================================
38
39/// The type of the function which starts up the Operating System. The BIOS
40/// finds and calls this function.
41pub type OsStartFn = extern "C" fn(&crate::Api) -> !;
42
43/// Any API function which can return an error, uses this error type.
44///
45/// Errors start at 1 to leave a niche for when packing into a `Result<T,
46/// Error>`.
47#[repr(u8)]
48#[derive(Clone, Debug, PartialEq, Eq)]
49pub enum Error {
50	/// An invalid device number was given to the function.
51	InvalidDevice = 1,
52	/// That function doesn't work at this time.
53	Unimplemented,
54	/// The underlying hardware reported some error. The numeric code is BIOS
55	/// implementation specific but may give some clues.
56	DeviceError,
57	/// The underlying hardware could not accept the given configuration. The
58	/// numeric code is BIOS implementation specific but may give some clues.
59	UnsupportedConfiguration,
60	/// You used a Block Device API but there was no media in the drive
61	NoMediaFound,
62	/// You used a Block Device API asked for a block the device doesn't have
63	BlockOutOfBounds,
64}
65
66/// An error that specifically means 'unable to convert integer to enum'
67#[derive(Debug, Copy, Clone)]
68pub struct EnumConversionFail();
69
70/// Describes a period of time, after which the BIOS should give up.
71#[repr(C)]
72#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
73pub struct Timeout(u32);
74
75/// Represents an instant in time between 2000-01-01T00:00:00Z and
76/// 2136-02-07T06:28:16Z.
77#[repr(C)]
78#[derive(Debug, Clone)]
79pub struct Time {
80	/// Seconds since the epoch
81	pub secs: u32,
82	/// Nanoseconds since the last second rolled over
83	pub nsecs: u32,
84}
85
86/// Represents a tick of some internal monotonic clock.
87///
88/// Usually runs at 1 kHz.
89#[repr(C)]
90#[derive(Debug, Clone)]
91pub struct Ticks(pub u64);
92
93make_ffi_enum!("The kinds of memory we know about",
94	MemoryKind, FfiMemoryKind, {
95	#[doc = "Read-write memory."]
96	#[doc = ""]
97	#[doc = "The OS is free to use Ram regions for code or data."]
98	Ram,
99	#[doc = "Read-only memory"]
100	#[doc = ""]
101	#[doc = "The OS is free to look inside Rom regions for ROM filing systems."]
102	Rom,
103	#[doc = "Used stack."]
104	#[doc = ""]
105	#[doc = "This is for information - the OS should not read or write here."]
106	StackUsed,
107	#[doc = "Free stack"]
108	#[doc = ""]
109	#[doc = "This is for information - the OS should not read or write here."]
110	StackFree,
111	#[doc = "Reserved memory region"]
112	#[doc = ""]
113	#[doc = "This is for information - the OS should not read or write here."]
114	Reserved
115});
116
117/// Represents a region in memory.
118#[repr(C)]
119#[derive(Debug, Clone)]
120pub struct MemoryRegion {
121	/// The address the region starts at
122	pub start: *mut u8,
123	/// The length of the region
124	pub length: usize,
125	/// The kind of memory found at this region
126	pub kind: FfiMemoryKind,
127}
128
129make_ffi_enum!("The kinds of power control we can do.",
130	PowerMode, FfiPowerMode, {
131	#[doc = "Turn the system power off"]
132	Off,
133	#[doc = "Reboot the main processor"]
134	Reset,
135	#[doc = "Reboot the main processor, but tell it to enter a bootloader mode"]
136	#[doc = "for programming."]
137	#[doc = ""]
138	#[doc = "Precisely what this will do will depend upon the BIOS. Some BIOSes"]
139	#[doc = "will not have a bootloader mode and this will do a regular reboot."]
140	Bootloader
141});
142
143// ============================================================================
144// Impls
145// ============================================================================
146
147// OsStartFn
148
149// Timeout
150
151impl Timeout {
152	/// Create a new timeout, in milliseconds.
153	pub fn new_ms(milliseconds: u32) -> Timeout {
154		Timeout(milliseconds)
155	}
156
157	/// Create a new timeout, in seconds.
158	pub fn new_secs(seconds: u16) -> Timeout {
159		let milliseconds = u32::from(seconds) * 1000;
160		Self::new_ms(milliseconds)
161	}
162
163	/// Get the timeout, in milliseconds
164	pub fn get_ms(self) -> u32 {
165		self.0
166	}
167}
168
169// Time
170
171impl core::fmt::Display for Time {
172	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
173		let timestamp: chrono::DateTime<chrono::Utc> = self.into();
174		write!(f, "{}", timestamp)
175	}
176}
177
178impl From<&Time> for chrono::DateTime<chrono::Utc> {
179	fn from(time: &Time) -> Self {
180		use chrono::prelude::*;
181		let our_epoch = Utc
182			.with_ymd_and_hms(2000, 1, 1, 0, 0, 0)
183			.unwrap()
184			.timestamp();
185		chrono::Utc
186			.timestamp_opt(i64::from(time.secs) + our_epoch, time.nsecs)
187			.unwrap()
188	}
189}
190
191// MemoryKind
192
193impl core::fmt::Display for MemoryKind {
194	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
195		write!(
196			f,
197			"{}",
198			match self {
199				MemoryKind::Rom => "ROM",
200				MemoryKind::Ram => "RAM",
201				MemoryKind::StackUsed => "StackUsed",
202				MemoryKind::StackFree => "StackFree",
203				MemoryKind::Reserved => "Reserved",
204			}
205		)
206	}
207}
208
209// MemoryRegion
210
211impl core::fmt::Display for MemoryRegion {
212	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
213		write!(
214			f,
215			"{} KiB {} @ {:p}..{:p}",
216			self.length / 1024,
217			self.kind.make_safe().unwrap_or(MemoryKind::Reserved),
218			self.start,
219			unsafe { self.start.add(self.length) },
220		)
221	}
222}
223
224// ============================================================================
225// End of File
226// ============================================================================