Merge branch 'ntp'
This commit is contained in:
commit
af10782500
@ -35,3 +35,4 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void);
|
||||
void MiscellaneousMenu_ChangeMenuCombo(void);
|
||||
void MiscellaneousMenu_SaveSettings(void);
|
||||
void MiscellaneousMenu_InputRedirection(void);
|
||||
void MiscellaneousMenu_SyncTimeDate(void);
|
@ -33,6 +33,7 @@ int socSocket(int domain, int type, int protocol);
|
||||
int socBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int socListen(int sockfd, int max_connections);
|
||||
int socAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
int socConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int socPoll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
int socSetsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
int socClose(int sockfd);
|
||||
|
33
sysmodules/rosalina/include/ntp.h
Normal file
33
sysmodules/rosalina/include/ntp.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
#include <time.h>
|
||||
|
||||
Result ntpGetTimeStamp(time_t *outTimestamp);
|
||||
Result ntpSetTimeDate(const struct tm *localt);
|
@ -27,6 +27,7 @@
|
||||
#include <3ds.h>
|
||||
#include "menus/miscellaneous.h"
|
||||
#include "input_redirection.h"
|
||||
#include "ntp.h"
|
||||
#include "memory.h"
|
||||
#include "draw.h"
|
||||
#include "hbloader.h"
|
||||
@ -38,11 +39,12 @@
|
||||
|
||||
Menu miscellaneousMenu = {
|
||||
"Miscellaneous options menu",
|
||||
.nbItems = 4,
|
||||
.nbItems = 5,
|
||||
{
|
||||
{ "Switch the hb. title to the current app.", METHOD, .method = &MiscellaneousMenu_SwitchBoot3dsxTargetTitle },
|
||||
{ "Change the menu combo", METHOD, .method = MiscellaneousMenu_ChangeMenuCombo },
|
||||
{ "Change the menu combo", METHOD, .method = &MiscellaneousMenu_ChangeMenuCombo },
|
||||
{ "Start InputRedirection", METHOD, .method = &MiscellaneousMenu_InputRedirection },
|
||||
{ "Sync time and date via NTP", METHOD, .method = &MiscellaneousMenu_SyncTimeDate },
|
||||
{ "Save settings", METHOD, .method = &MiscellaneousMenu_SaveSettings },
|
||||
}
|
||||
};
|
||||
@ -316,3 +318,85 @@ void MiscellaneousMenu_InputRedirection(void)
|
||||
}
|
||||
while(!(waitInput() & BUTTON_B) && !terminationRequest);
|
||||
}
|
||||
|
||||
void MiscellaneousMenu_SyncTimeDate(void)
|
||||
{
|
||||
u32 posY;
|
||||
u32 input = 0;
|
||||
|
||||
Result res;
|
||||
bool cantStart = false;
|
||||
|
||||
bool isSocURegistered;
|
||||
|
||||
time_t t;
|
||||
struct tm localt = {0};
|
||||
|
||||
res = srvIsServiceRegistered(&isSocURegistered, "soc:U");
|
||||
cantStart = R_FAILED(res) || !isSocURegistered;
|
||||
|
||||
int utcOffset = 12;
|
||||
int absOffset;
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu");
|
||||
|
||||
//posY = Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Current UTC offset: ");
|
||||
absOffset = utcOffset - 12;
|
||||
absOffset = absOffset < 0 ? -absOffset : absOffset;
|
||||
posY = Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Current UTC offset: %c%02d", utcOffset < 12 ? '-' : '+', absOffset);
|
||||
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Use DPAD Left/Right to change offset.\nPress A when done.") + SPACING_Y;
|
||||
|
||||
input = waitInput();
|
||||
|
||||
if(input & BUTTON_LEFT) utcOffset = (24 + utcOffset - 1) % 24; // ensure utcOffset >= 0
|
||||
if(input & BUTTON_RIGHT) utcOffset = (utcOffset + 1) % 24;
|
||||
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
}
|
||||
while(!(input & (BUTTON_A | BUTTON_B)) && !terminationRequest);
|
||||
|
||||
if (input & BUTTON_B)
|
||||
return;
|
||||
|
||||
utcOffset -= 12;
|
||||
|
||||
res = srvIsServiceRegistered(&isSocURegistered, "soc:U");
|
||||
cantStart = R_FAILED(res) || !isSocURegistered;
|
||||
res = 0;
|
||||
if(!cantStart)
|
||||
{
|
||||
res = ntpGetTimeStamp(&t);
|
||||
if(R_SUCCEEDED(res))
|
||||
{
|
||||
t += 3600 * utcOffset;
|
||||
gmtime_r(&t, &localt);
|
||||
res = ntpSetTimeDate(&localt);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu");
|
||||
|
||||
absOffset = utcOffset;
|
||||
absOffset = absOffset < 0 ? -absOffset : absOffset;
|
||||
Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Current UTC offset: %c%02d", utcOffset < 0 ? '-' : '+', absOffset);
|
||||
if (cantStart)
|
||||
posY = Draw_DrawFormattedString(10, posY + 2 * SPACING_Y, COLOR_WHITE, "Can't sync time/date before the system\nhas finished loading.") + SPACING_Y;
|
||||
else if (R_FAILED(res))
|
||||
posY = Draw_DrawFormattedString(10, posY + 2 * SPACING_Y, COLOR_WHITE, "Operation failed (%08lx).", (u32)res) + SPACING_Y;
|
||||
else
|
||||
posY = Draw_DrawFormattedString(10, posY + 2 * SPACING_Y, COLOR_WHITE, "Timedate & RTC updated successfully.\nYou may need to reboot to see the changes.") + SPACING_Y;
|
||||
|
||||
input = waitInput();
|
||||
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
}
|
||||
while(!(input & BUTTON_B) && !terminationRequest);
|
||||
|
||||
}
|
@ -312,6 +312,47 @@ int socAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int socConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
int ret = 0;
|
||||
socklen_t tmp_addrlen = 0;
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
u8 tmpaddr[0x1c];
|
||||
|
||||
memset(tmpaddr, 0, 0x1c);
|
||||
|
||||
if(addr->sa_family == AF_INET)
|
||||
tmp_addrlen = 8;
|
||||
else
|
||||
tmp_addrlen = 0x1c;
|
||||
|
||||
if(addrlen < tmp_addrlen)
|
||||
return -1;
|
||||
|
||||
tmpaddr[0] = tmp_addrlen;
|
||||
tmpaddr[1] = addr->sa_family;
|
||||
memcpy(&tmpaddr[2], &addr->sa_data, tmp_addrlen-2);
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(0x6,2,4); // 0x60084
|
||||
cmdbuf[1] = (u32)sockfd;
|
||||
cmdbuf[2] = (u32)addrlen;
|
||||
cmdbuf[3] = IPC_Desc_CurProcessId();
|
||||
cmdbuf[5] = IPC_Desc_StaticBuffer(tmp_addrlen,0);
|
||||
cmdbuf[6] = (u32)tmpaddr;
|
||||
|
||||
ret = svcSendSyncRequest(SOCU_handle);
|
||||
if(ret != 0) return -1;
|
||||
|
||||
ret = (int)cmdbuf[1];
|
||||
if(ret == 0)
|
||||
ret = _net_convert_error(cmdbuf[2]);
|
||||
|
||||
if(ret < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socPoll(struct pollfd *fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
int ret = 0;
|
||||
|
192
sysmodules/rosalina/source/ntp.c
Normal file
192
sysmodules/rosalina/source/ntp.c
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include <3ds.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include "utils.h"
|
||||
#include "minisoc.h"
|
||||
|
||||
#define NUM2BCD(n) ((n<99) ? (((n/10)*0x10)|(n%10)) : 0x99)
|
||||
|
||||
#define NTP_TIMESTAMP_DELTA 2208988800ull
|
||||
|
||||
typedef struct RtcTime {
|
||||
// From 3dbrew
|
||||
u8 seconds;
|
||||
u8 minutes;
|
||||
u8 hours;
|
||||
u8 dayofweek;
|
||||
u8 dayofmonth;
|
||||
u8 month;
|
||||
u8 year;
|
||||
u8 leapcount;
|
||||
} RtcTime;
|
||||
|
||||
// From https://github.com/lettier/ntpclient/blob/master/source/c/main.c
|
||||
|
||||
typedef struct NtpPacket
|
||||
{
|
||||
|
||||
u8 li_vn_mode; // Eight bits. li, vn, and mode.
|
||||
// li. Two bits. Leap indicator.
|
||||
// vn. Three bits. Version number of the protocol.
|
||||
// mode. Three bits. Client will pick mode 3 for client.
|
||||
|
||||
u8 stratum; // Eight bits. Stratum level of the local clock.
|
||||
u8 poll; // Eight bits. Maximum interval between successive messages.
|
||||
u8 precision; // Eight bits. Precision of the local clock.
|
||||
|
||||
u32 rootDelay; // 32 bits. Total round trip delay time.
|
||||
u32 rootDispersion; // 32 bits. Max error aloud from primary clock source.
|
||||
u32 refId; // 32 bits. Reference clock identifier.
|
||||
|
||||
u32 refTm_s; // 32 bits. Reference time-stamp seconds.
|
||||
u32 refTm_f; // 32 bits. Reference time-stamp fraction of a second.
|
||||
|
||||
u32 origTm_s; // 32 bits. Originate time-stamp seconds.
|
||||
u32 origTm_f; // 32 bits. Originate time-stamp fraction of a second.
|
||||
|
||||
u32 rxTm_s; // 32 bits. Received time-stamp seconds.
|
||||
u32 rxTm_f; // 32 bits. Received time-stamp fraction of a second.
|
||||
|
||||
u32 txTm_s; // 32 bits and the most important field the client cares about. Transmit time-stamp seconds.
|
||||
u32 txTm_f; // 32 bits. Transmit time-stamp fraction of a second.
|
||||
|
||||
} NtpPacket; // Total: 384 bits or 48 bytes.
|
||||
|
||||
void rtcToBcd(u8 *out, const RtcTime *in)
|
||||
{
|
||||
memcpy(out, in, 8);
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
u8 units = out[i] % 10;
|
||||
u8 tens = (out[i] - units) / 10;
|
||||
out[i] = (tens << 4) | units;
|
||||
}
|
||||
}
|
||||
|
||||
Result ntpGetTimeStamp(time_t *outTimestamp)
|
||||
{
|
||||
Result res = 0;
|
||||
struct linger linger;
|
||||
res = miniSocInit();
|
||||
if(R_FAILED(res))
|
||||
return res;
|
||||
|
||||
int sock = socSocket(AF_INET, SOCK_DGRAM, 0);
|
||||
struct sockaddr_in servAddr = {0}; // Server address data structure.
|
||||
NtpPacket packet = {0};
|
||||
|
||||
// Set the first byte's bits to 00,011,011 for li = 0, vn = 3, and mode = 3. The rest will be left set to zero.
|
||||
packet.li_vn_mode = 0x1b;
|
||||
|
||||
// Zero out the server address structure.
|
||||
servAddr.sin_family = AF_INET;
|
||||
|
||||
// Copy the server's IP address to the server address structure.
|
||||
|
||||
servAddr.sin_addr.s_addr = htonl(0xD8EF2300); // 216.239.35.0 time1.google.com
|
||||
// Convert the port number integer to network big-endian style and save it to the server address structure.
|
||||
|
||||
servAddr.sin_port = htons(123);
|
||||
|
||||
// Call up the server using its IP address and port number.
|
||||
res = -1;
|
||||
if(socConnect(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if(soc_send(sock, &packet, sizeof(NtpPacket), 0) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if(soc_recv(sock, &packet, sizeof(NtpPacket), 0) < 0)
|
||||
goto cleanup;
|
||||
|
||||
res = 0;
|
||||
|
||||
// These two fields contain the time-stamp seconds as the packet left the NTP server.
|
||||
// The number of seconds correspond to the seconds passed since 1900.
|
||||
// ntohl() converts the bit/byte order from the network's to host's "endianness".
|
||||
|
||||
packet.txTm_s = ntohl(packet.txTm_s); // Time-stamp seconds.
|
||||
packet.txTm_f = ntohl(packet.txTm_f); // Time-stamp fraction of a second.
|
||||
|
||||
// Extract the 32 bits that represent the time-stamp seconds (since NTP epoch) from when the packet left the server.
|
||||
// Subtract 70 years worth of seconds from the seconds since 1900.
|
||||
// This leaves the seconds since the UNIX epoch of 1970.
|
||||
// (1900)------------------(1970)**************************************(Time Packet Left the Server)
|
||||
*outTimestamp = (time_t)(packet.txTm_s - NTP_TIMESTAMP_DELTA);
|
||||
|
||||
cleanup:
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 0;
|
||||
socSetsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger));
|
||||
|
||||
socClose(sock);
|
||||
miniSocExit();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Result ntpSetTimeDate(const struct tm *localt)
|
||||
{
|
||||
Result res = mcuHwcInit();
|
||||
if (R_FAILED(res)) return res;
|
||||
|
||||
|
||||
res = cfguInit();
|
||||
if (R_FAILED(res)) goto cleanup;
|
||||
|
||||
// First, set the config RTC offset to 0
|
||||
u8 rtcOff = 0;
|
||||
res = CFG_SetConfigInfoBlk4(1, 0x10000, &rtcOff);
|
||||
if (R_FAILED(res)) goto cleanup;
|
||||
|
||||
u8 yr = (u8)(localt->tm_year - 100);
|
||||
// Update the RTC
|
||||
u8 bcd[8];
|
||||
RtcTime lt = {
|
||||
.seconds = (u8)localt->tm_sec,
|
||||
.minutes = (u8)localt->tm_min,
|
||||
.hours = (u8)localt->tm_hour,
|
||||
.dayofweek = (u8)localt->tm_wday,
|
||||
.dayofmonth = (u8)localt->tm_mday,
|
||||
.month = (u8)(localt->tm_mon + 1),
|
||||
.year = yr,
|
||||
.leapcount = 0,
|
||||
};
|
||||
rtcToBcd(bcd, <);
|
||||
|
||||
res = MCUHWC_WriteRegister(0x30, bcd, 7);
|
||||
if (R_FAILED(res)) goto cleanup;
|
||||
|
||||
// Save the config changes
|
||||
res = CFG_UpdateConfigSavegame();
|
||||
cleanup:
|
||||
mcuHwcExit();
|
||||
cfguExit();
|
||||
return res;
|
||||
}
|
Reference in New Issue
Block a user